2024-09-25 15:00:55 +02:00
|
|
|
#include "Pipe.hpp"
|
|
|
|
|
#include "Device.hpp"
|
|
|
|
|
#include "Registers.hpp"
|
|
|
|
|
#include "Renderer.hpp"
|
|
|
|
|
#include "gnm/mmio.hpp"
|
|
|
|
|
#include "gnm/pm4.hpp"
|
2024-10-12 04:24:58 +02:00
|
|
|
#include "orbis/KernelContext.hpp"
|
2025-11-30 13:46:37 +01:00
|
|
|
#include "orbis/vmem.hpp"
|
|
|
|
|
#include "rx/AddressRange.hpp"
|
|
|
|
|
#include "rx/EnumBitSet.hpp"
|
2025-10-04 13:06:47 +02:00
|
|
|
#include "rx/print.hpp"
|
2024-09-25 15:00:55 +02:00
|
|
|
#include "vk.hpp"
|
2024-09-30 21:43:21 +02:00
|
|
|
#include <bit>
|
2024-09-25 15:00:55 +02:00
|
|
|
#include <cstdio>
|
2024-10-15 17:35:17 +02:00
|
|
|
#include <mutex>
|
2024-09-25 15:00:55 +02:00
|
|
|
#include <rx/bits.hpp>
|
|
|
|
|
#include <rx/die.hpp>
|
2024-11-20 21:22:37 +01:00
|
|
|
#include <rx/format.hpp>
|
2024-09-25 15:00:55 +02:00
|
|
|
#include <vulkan/vulkan_core.h>
|
|
|
|
|
|
|
|
|
|
using namespace amdgpu;
|
|
|
|
|
|
2024-10-12 04:24:58 +02:00
|
|
|
enum GraphicsCoreEvent {
|
|
|
|
|
kGcEventCompute0RelMem = 0x00,
|
|
|
|
|
kGcEventCompute1RelMem = 0x01,
|
|
|
|
|
kGcEventCompute2RelMem = 0x02,
|
|
|
|
|
kGcEventCompute3RelMem = 0x03,
|
|
|
|
|
kGcEventCompute4RelMem = 0x04,
|
|
|
|
|
kGcEventCompute5RelMem = 0x05,
|
|
|
|
|
kGcEventCompute6RelMem = 0x06,
|
|
|
|
|
kGcEventGfxEop = 0x40,
|
|
|
|
|
kGcEventClockSet = 0x84,
|
|
|
|
|
};
|
|
|
|
|
|
2024-11-20 21:22:37 +01:00
|
|
|
struct RegSpan {
|
|
|
|
|
std::uint32_t offset;
|
|
|
|
|
std::uint32_t count;
|
|
|
|
|
};
|
|
|
|
|
|
2024-09-25 15:00:55 +02:00
|
|
|
static Scheduler createGfxScheduler(int index) {
|
|
|
|
|
auto queue = vk::context->presentQueue;
|
|
|
|
|
auto family = vk::context->presentQueueFamily;
|
|
|
|
|
|
|
|
|
|
if (index != 0) {
|
|
|
|
|
for (auto [otherQueue, otherFamily] : vk::context->graphicsQueues) {
|
|
|
|
|
if (family != otherFamily) {
|
|
|
|
|
queue = otherQueue;
|
|
|
|
|
family = otherFamily;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Scheduler{queue, family};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Scheduler createComputeScheduler(int index) {
|
|
|
|
|
auto &compQueues = vk::context->computeQueues;
|
2024-10-12 04:24:58 +02:00
|
|
|
|
|
|
|
|
if (compQueues.empty()) {
|
|
|
|
|
// Workaround for LLVM device
|
|
|
|
|
return createGfxScheduler(index);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-25 15:00:55 +02:00
|
|
|
auto [queue, family] = compQueues[index % compQueues.size()];
|
|
|
|
|
|
|
|
|
|
return Scheduler{queue, family};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool compare(int cmpFn, std::uint32_t poll, std::uint32_t mask,
|
|
|
|
|
std::uint32_t ref) {
|
|
|
|
|
poll &= mask;
|
|
|
|
|
ref &= mask;
|
|
|
|
|
|
|
|
|
|
switch (cmpFn) {
|
|
|
|
|
case 0:
|
|
|
|
|
return true;
|
|
|
|
|
case 1:
|
|
|
|
|
return poll < ref;
|
|
|
|
|
case 2:
|
|
|
|
|
return poll <= ref;
|
|
|
|
|
case 3:
|
|
|
|
|
return poll == ref;
|
|
|
|
|
case 4:
|
|
|
|
|
return poll != ref;
|
|
|
|
|
case 5:
|
|
|
|
|
return poll >= ref;
|
|
|
|
|
case 6:
|
|
|
|
|
return poll > ref;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
ComputePipe::ComputePipe(int index)
|
|
|
|
|
: scheduler(createComputeScheduler(index)), index(index) {
|
2024-09-25 15:00:55 +02:00
|
|
|
for (auto &handler : commandHandlers) {
|
|
|
|
|
handler = &ComputePipe::unknownPacket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
commandHandlers[gnm::IT_NOP] = &ComputePipe::handleNop;
|
2024-10-15 17:35:17 +02:00
|
|
|
commandHandlers[gnm::IT_SET_SH_REG] = &ComputePipe::setShReg;
|
|
|
|
|
commandHandlers[gnm::IT_DISPATCH_DIRECT] = &ComputePipe::dispatchDirect;
|
|
|
|
|
commandHandlers[gnm::IT_DISPATCH_INDIRECT] = &ComputePipe::dispatchIndirect;
|
|
|
|
|
commandHandlers[gnm::IT_RELEASE_MEM] = &ComputePipe::releaseMem;
|
|
|
|
|
commandHandlers[gnm::IT_WAIT_REG_MEM] = &ComputePipe::waitRegMem;
|
|
|
|
|
commandHandlers[gnm::IT_WRITE_DATA] = &ComputePipe::writeData;
|
2024-10-15 17:54:25 +02:00
|
|
|
commandHandlers[gnm::IT_INDIRECT_BUFFER] = &ComputePipe::indirectBuffer;
|
2024-10-15 18:02:37 +02:00
|
|
|
commandHandlers[gnm::IT_ACQUIRE_MEM] = &ComputePipe::acquireMem;
|
2024-11-13 21:53:08 +01:00
|
|
|
commandHandlers[gnm::IT_DMA_DATA] = &ComputePipe::dmaData;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ComputePipe::processAllRings() {
|
|
|
|
|
bool allProcessed = true;
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
for (auto &queue : queues) {
|
|
|
|
|
std::lock_guard lock(queueMtx[&queue - queues]);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
for (auto &ring : queue) {
|
2024-10-15 17:54:25 +02:00
|
|
|
currentQueueId = &ring - queue;
|
2024-10-15 17:35:17 +02:00
|
|
|
if (!processRing(ring)) {
|
|
|
|
|
allProcessed = false;
|
|
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return allProcessed;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool ComputePipe::processRing(Ring &ring) {
|
|
|
|
|
if (ring.size == 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
if (ring.rptrReportLocation != nullptr) {
|
|
|
|
|
// FIXME: verify
|
|
|
|
|
ring.rptr = ring.base + *ring.rptrReportLocation;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-22 18:04:32 +02:00
|
|
|
auto origRptr = ring.rptr;
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
while (ring.rptr != ring.wptr) {
|
|
|
|
|
if (ring.rptr >= ring.base + ring.size) {
|
|
|
|
|
ring.rptr = ring.base;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
auto header = *ring.rptr;
|
|
|
|
|
auto type = rx::getBits(header, 31, 30);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
if (type == 3) {
|
|
|
|
|
auto op = rx::getBits(header, 15, 8);
|
|
|
|
|
auto len = rx::getBits(header, 29, 16) + 2;
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
// std::fprintf(stderr, "queue %d: %s\n", ring.indirectLevel,
|
|
|
|
|
// gnm::pm4OpcodeToString(op));
|
|
|
|
|
|
|
|
|
|
if (op == gnm::IT_COND_EXEC) {
|
|
|
|
|
rx::die("unimplemented COND_EXEC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto handler = commandHandlers[op];
|
|
|
|
|
if (!(this->*handler)(ring)) {
|
|
|
|
|
if (ring.rptrReportLocation != nullptr) {
|
|
|
|
|
*ring.rptrReportLocation = ring.rptr - ring.base;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ring.rptr += len;
|
|
|
|
|
continue;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
if (type == 2) {
|
|
|
|
|
++ring.rptr;
|
|
|
|
|
continue;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unexpected pm4 packet type {}", type);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-22 18:04:32 +02:00
|
|
|
if (origRptr != ring.rptr && ring.rptrReportLocation != nullptr) {
|
2024-10-15 17:35:17 +02:00
|
|
|
*ring.rptrReportLocation = ring.rptr - ring.base;
|
|
|
|
|
}
|
2024-10-15 18:02:37 +02:00
|
|
|
|
|
|
|
|
break;
|
2024-10-15 17:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:54:25 +02:00
|
|
|
void ComputePipe::setIndirectRing(int queueId, int indirectLevel, Ring ring) {
|
|
|
|
|
if (indirectLevel != 1) {
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unexpected compute indirect ring indirect level {}",
|
2024-10-15 17:54:25 +02:00
|
|
|
ring.indirectLevel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ring.indirectLevel = indirectLevel;
|
2025-10-04 13:06:47 +02:00
|
|
|
rx::println(stderr, "mapQueue: {}, {}, {}", (void *)ring.base,
|
2025-10-04 13:23:42 +02:00
|
|
|
(void *)ring.wptr, ring.size);
|
2024-10-15 17:54:25 +02:00
|
|
|
|
|
|
|
|
queues[1 - ring.indirectLevel][queueId] = ring;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
void ComputePipe::mapQueue(int queueId, Ring ring,
|
2025-10-04 23:09:42 +02:00
|
|
|
std::unique_lock<rx::shared_mutex> &lock) {
|
2024-10-15 17:35:17 +02:00
|
|
|
if (ring.indirectLevel < 0 || ring.indirectLevel > 1) {
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unexpected compute ring indirect level {}", ring.indirectLevel);
|
2024-10-15 17:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ring.indirectLevel == 0) {
|
|
|
|
|
waitForIdle(queueId, lock);
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-13 21:53:08 +01:00
|
|
|
std::println(stderr, "mapQueue: {}, {}, {}, {}", (void *)ring.base,
|
|
|
|
|
(void *)ring.wptr, ring.size, (void *)ring.doorbell);
|
2024-10-15 17:35:17 +02:00
|
|
|
|
|
|
|
|
queues[1 - ring.indirectLevel][queueId] = ring;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ComputePipe::waitForIdle(int queueId,
|
2025-10-04 23:09:42 +02:00
|
|
|
std::unique_lock<rx::shared_mutex> &lock) {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto &ring = queues[1][queueId];
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
if (ring.size == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ring.rptr == ring.wptr) {
|
|
|
|
|
return;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
lock.unlock();
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
|
|
|
|
lock.lock();
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
void ComputePipe::submit(int queueId, std::uint32_t offset) {
|
|
|
|
|
auto &ring = queues[1][queueId];
|
|
|
|
|
ring.wptr = ring.base + offset;
|
|
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool ComputePipe::setShReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16);
|
|
|
|
|
auto offset = ring.rptr[1] & 0xffff;
|
|
|
|
|
auto index = ring.rptr[1] >> 26;
|
|
|
|
|
auto data = ring.rptr + 2;
|
|
|
|
|
|
|
|
|
|
if (Registers::ShaderConfig::kMmioOffset + offset <
|
|
|
|
|
Registers::ComputeConfig::kMmioOffset) {
|
|
|
|
|
rx::die(
|
|
|
|
|
"unexpected compute pipe offset %x %s", offset,
|
|
|
|
|
gnm::mmio::registerName(Registers::ShaderConfig::kMmioOffset + offset));
|
|
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
offset -= Registers::ComputeConfig::kMmioOffset -
|
|
|
|
|
Registers::ShaderConfig::kMmioOffset;
|
|
|
|
|
|
|
|
|
|
rx::dieIf(
|
|
|
|
|
(offset + len) * sizeof(std::uint32_t) > sizeof(Registers::ComputeConfig),
|
2025-10-04 13:23:42 +02:00
|
|
|
"out of compute regs, offset: {:x}, count {}, {}\n", offset, len,
|
2024-10-15 17:35:17 +02:00
|
|
|
gnm::mmio::registerName(Registers::ShaderConfig::kMmioOffset + offset));
|
|
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < len; ++i) {
|
|
|
|
|
std::fprintf(stderr, "writing to %s value %x\n",
|
|
|
|
|
gnm::mmio::registerName(Registers::ShaderConfig::kMmioOffset +
|
|
|
|
|
offset + i),
|
|
|
|
|
data[i]);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
std::memcpy(ring.doorbell + offset, const_cast<const uint32_t *>(data),
|
|
|
|
|
sizeof(std::uint32_t) * len);
|
2024-10-15 17:35:17 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ComputePipe::dispatchDirect(Ring &ring) {
|
|
|
|
|
auto config = std::bit_cast<Registers::ComputeConfig *>(ring.doorbell);
|
|
|
|
|
auto dimX = ring.rptr[1];
|
|
|
|
|
auto dimY = ring.rptr[2];
|
|
|
|
|
auto dimZ = ring.rptr[3];
|
|
|
|
|
auto dispatchInitiator = ring.rptr[4];
|
|
|
|
|
config->computeDispatchInitiator = dispatchInitiator;
|
|
|
|
|
|
|
|
|
|
amdgpu::dispatch(device->caches[ring.vmId], scheduler, *config, dimX, dimY,
|
|
|
|
|
dimZ);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ComputePipe::dispatchIndirect(Ring &ring) {
|
|
|
|
|
auto config = std::bit_cast<Registers::ComputeConfig *>(ring.doorbell);
|
|
|
|
|
auto offset = ring.rptr[1];
|
|
|
|
|
auto dispatchInitiator = ring.rptr[2];
|
|
|
|
|
|
|
|
|
|
config->computeDispatchInitiator = dispatchInitiator;
|
|
|
|
|
auto buffer = RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(
|
|
|
|
|
drawIndexIndirPatchBase + offset);
|
|
|
|
|
|
|
|
|
|
auto dimX = buffer[0];
|
|
|
|
|
auto dimY = buffer[1];
|
|
|
|
|
auto dimZ = buffer[2];
|
|
|
|
|
|
|
|
|
|
amdgpu::dispatch(device->caches[ring.vmId], scheduler, *config, dimX, dimY,
|
|
|
|
|
dimZ);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool ComputePipe::releaseMem(Ring &ring) {
|
|
|
|
|
auto eventCntl = ring.rptr[1];
|
|
|
|
|
auto dataCntl = ring.rptr[2];
|
|
|
|
|
auto addressLo = ring.rptr[3] & ~3;
|
|
|
|
|
auto addressHi = ring.rptr[4] & ((1 << 16) - 1);
|
|
|
|
|
auto dataLo = ring.rptr[5];
|
|
|
|
|
auto dataHi = ring.rptr[6];
|
|
|
|
|
|
|
|
|
|
auto eventIndex = rx::getBits(eventCntl, 11, 8);
|
|
|
|
|
auto eventType = rx::getBits(eventCntl, 5, 0);
|
|
|
|
|
auto dataSel = rx::getBits(dataCntl, 31, 29);
|
|
|
|
|
auto intSel = rx::getBits(dataCntl, 25, 24);
|
|
|
|
|
|
|
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
auto pointer = RemoteMemory{ring.vmId}.getPointer<std::uint64_t>(address);
|
|
|
|
|
|
|
|
|
|
switch (dataSel) {
|
|
|
|
|
case 0: // none
|
|
|
|
|
break;
|
|
|
|
|
case 1: // 32 bit, low
|
|
|
|
|
*reinterpret_cast<std::uint32_t *>(pointer) = dataLo;
|
|
|
|
|
break;
|
|
|
|
|
case 2: // 64 bit
|
|
|
|
|
*pointer = dataLo | (static_cast<std::uint64_t>(dataHi) << 32);
|
|
|
|
|
break;
|
|
|
|
|
case 3: // 64 bit, global GPU clock
|
|
|
|
|
*pointer = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
|
|
|
std::chrono::system_clock::now().time_since_epoch())
|
|
|
|
|
.count();
|
|
|
|
|
break;
|
|
|
|
|
case 4: // 64 bit, perf counter
|
|
|
|
|
*pointer = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
|
|
|
std::chrono::steady_clock::now().time_since_epoch())
|
|
|
|
|
.count();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unimplemented event release mem data {:#x}", dataSel);
|
2024-10-15 17:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (intSel) {
|
2025-10-10 18:56:11 +02:00
|
|
|
orbis::g_context->deviceEventEmitter->emit(
|
2024-11-25 01:06:33 +01:00
|
|
|
orbis::kEvFiltGraphicsCore,
|
|
|
|
|
[=, this](orbis::KNote *note) -> std::optional<std::int64_t> {
|
|
|
|
|
if (note->event.ident == kGcEventCompute0RelMem + index) {
|
|
|
|
|
return dataLo | (static_cast<std::uint64_t>(dataHi) << 32);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
});
|
2024-10-15 17:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ComputePipe::waitRegMem(Ring &ring) {
|
|
|
|
|
auto engine = rx::getBit(ring.rptr[1], 8);
|
|
|
|
|
auto memSpace = rx::getBit(ring.rptr[1], 4);
|
|
|
|
|
auto function = rx::getBits(ring.rptr[1], 2, 0);
|
|
|
|
|
auto pollAddressLo = ring.rptr[2];
|
|
|
|
|
auto pollAddressHi = ring.rptr[3] & ((1 << 16) - 1);
|
|
|
|
|
auto reference = ring.rptr[4];
|
|
|
|
|
auto mask = ring.rptr[5];
|
|
|
|
|
auto pollInterval = ring.rptr[6];
|
|
|
|
|
|
|
|
|
|
std::uint32_t pollData;
|
|
|
|
|
|
|
|
|
|
if (memSpace == 0) {
|
|
|
|
|
pollData = *getMmRegister(ring, pollAddressLo & ((1 << 16) - 1));
|
|
|
|
|
} else {
|
|
|
|
|
auto pollAddress = (pollAddressLo & ~3) |
|
|
|
|
|
(static_cast<std::uint64_t>(pollAddressHi) << 32);
|
|
|
|
|
pollData = *RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(pollAddress);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return compare(function, pollData, mask, reference);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ComputePipe::writeData(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16) - 1;
|
|
|
|
|
auto control = ring.rptr[1];
|
|
|
|
|
auto dstAddressLo = ring.rptr[2];
|
|
|
|
|
auto dstAddressHi = ring.rptr[3];
|
|
|
|
|
auto data = ring.rptr + 4;
|
|
|
|
|
|
|
|
|
|
auto engineSel = rx::getBits(control, 31, 30);
|
|
|
|
|
auto wrConfirm = rx::getBit(control, 20);
|
|
|
|
|
auto wrOneAddress = rx::getBit(control, 16);
|
|
|
|
|
auto dstSel = rx::getBits(control, 11, 8);
|
|
|
|
|
|
|
|
|
|
std::uint32_t *dstPointer = nullptr;
|
|
|
|
|
|
|
|
|
|
switch (dstSel) {
|
|
|
|
|
case 0: // memory mapped register
|
|
|
|
|
dstPointer = getMmRegister(ring, dstAddressLo & ((1 << 16) - 1));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: // memory sync
|
|
|
|
|
case 2: // TC L2
|
|
|
|
|
case 5: { // memory async
|
|
|
|
|
auto address =
|
|
|
|
|
(dstAddressLo & ~3) | (static_cast<std::uint64_t>(dstAddressHi) << 32);
|
|
|
|
|
dstPointer = RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unimplemented write data, dst sel = {:#x}", dstSel);
|
2024-10-15 17:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wrOneAddress) {
|
|
|
|
|
for (std::uint32_t i = 0; i < len; ++i) {
|
|
|
|
|
*dstPointer = data[i];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-04-05 21:50:45 +02:00
|
|
|
std::memcpy(dstPointer, const_cast<const uint32_t *>(data),
|
|
|
|
|
len * sizeof(std::uint32_t));
|
2024-10-15 17:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:54:25 +02:00
|
|
|
bool ComputePipe::indirectBuffer(Ring &ring) {
|
|
|
|
|
rx::dieIf(ring.indirectLevel < 0, "unexpected indirect buffer from CP");
|
|
|
|
|
|
|
|
|
|
auto addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
auto addressHi = ring.rptr[2] & ((1 << 8) - 1);
|
|
|
|
|
int vmId = ring.rptr[3] >> 24;
|
|
|
|
|
auto ibSize = ring.rptr[3] & ((1 << 20) - 1);
|
|
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
|
2024-10-15 18:02:37 +02:00
|
|
|
vmId = ring.vmId;
|
|
|
|
|
|
2024-10-15 17:54:25 +02:00
|
|
|
auto rptr = RemoteMemory{vmId}.getPointer<std::uint32_t>(address);
|
2024-10-15 18:02:37 +02:00
|
|
|
auto indirectRing = Ring::createFromRange(vmId, rptr, ibSize);
|
|
|
|
|
indirectRing.doorbell = ring.doorbell;
|
|
|
|
|
setIndirectRing(currentQueueId, ring.indirectLevel + 1, indirectRing);
|
2024-10-15 17:54:25 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 18:02:37 +02:00
|
|
|
bool ComputePipe::acquireMem(Ring &ring) { return true; }
|
|
|
|
|
|
2024-11-13 21:53:08 +01:00
|
|
|
bool ComputePipe::dmaData(Ring &ring) {
|
|
|
|
|
auto control = ring.rptr[1];
|
|
|
|
|
auto srcAddressLo = ring.rptr[2];
|
|
|
|
|
auto data = srcAddressLo;
|
|
|
|
|
auto srcAddressHi = ring.rptr[3];
|
|
|
|
|
auto dstAddressLo = ring.rptr[4];
|
|
|
|
|
auto dstAddressHi = ring.rptr[5];
|
|
|
|
|
auto cmdSize = ring.rptr[6];
|
|
|
|
|
auto size = rx::getBits(cmdSize, 20, 0);
|
|
|
|
|
|
|
|
|
|
auto engine = rx::getBit(control, 0);
|
|
|
|
|
auto srcVolatile = rx::getBit(control, 15);
|
|
|
|
|
|
|
|
|
|
// 0 - dstAddress using das
|
|
|
|
|
// 1 - gds
|
|
|
|
|
// 3 - dstAddress using L2
|
|
|
|
|
auto dstSel = rx::getBits(control, 21, 20);
|
|
|
|
|
|
|
|
|
|
// 0 - LRU
|
|
|
|
|
// 1 - Stream
|
|
|
|
|
// 2 - Bypass
|
|
|
|
|
auto dstCachePolicy = rx::getBits(control, 26, 25);
|
|
|
|
|
|
|
|
|
|
auto dstVolatile = rx::getBit(control, 27);
|
|
|
|
|
|
|
|
|
|
// 0 - srcAddress using sas
|
|
|
|
|
// 1 - gds
|
|
|
|
|
// 2 - data
|
|
|
|
|
// 3 - srcAddress using L2
|
|
|
|
|
auto srcSel = rx::getBits(control, 30, 29);
|
|
|
|
|
|
|
|
|
|
auto cpSync = rx::getBit(control, 31);
|
|
|
|
|
|
|
|
|
|
auto dataDisWc = rx::getBit(cmdSize, 21);
|
|
|
|
|
|
|
|
|
|
// 0 - none
|
|
|
|
|
// 1 - 8 in 16
|
|
|
|
|
// 2 - 8 in 32
|
|
|
|
|
// 3 - 8 in 64
|
|
|
|
|
auto dstSwap = rx::getBits(cmdSize, 25, 24);
|
|
|
|
|
|
|
|
|
|
// 0 - memory
|
|
|
|
|
// 1 - register
|
|
|
|
|
auto sas = rx::getBit(cmdSize, 26);
|
|
|
|
|
|
|
|
|
|
// 0 - memory
|
|
|
|
|
// 1 - register
|
|
|
|
|
auto das = rx::getBit(cmdSize, 27);
|
|
|
|
|
|
|
|
|
|
auto saic = rx::getBit(cmdSize, 28);
|
|
|
|
|
auto daic = rx::getBit(cmdSize, 29);
|
|
|
|
|
auto rawWait = rx::getBit(cmdSize, 30);
|
|
|
|
|
|
|
|
|
|
void *dst = nullptr;
|
|
|
|
|
switch (dstSel) {
|
|
|
|
|
case 3:
|
|
|
|
|
case 0:
|
|
|
|
|
if (dstSel == 3 || das == 0) {
|
|
|
|
|
auto dstAddress =
|
|
|
|
|
dstAddressLo | (static_cast<std::uint64_t>(dstAddressHi) << 32);
|
|
|
|
|
dst = amdgpu::RemoteMemory{ring.vmId}.getPointer(dstAddress);
|
|
|
|
|
device->caches[ring.vmId].invalidate(
|
|
|
|
|
scheduler, rx::AddressRange::fromBeginSize(dstAddress, size));
|
|
|
|
|
} else {
|
|
|
|
|
dst = getMmRegister(ring, dstAddressLo / sizeof(std::uint32_t));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
dst = device->caches[ring.vmId].getGdsBuffer().getData() + dstAddressLo;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("IT_DMA_DATA: unexpected dstSel {}", dstSel);
|
2024-11-13 21:53:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *src = nullptr;
|
|
|
|
|
std::uint32_t srcSize = 0;
|
|
|
|
|
switch (srcSel) {
|
|
|
|
|
case 3:
|
|
|
|
|
case 0:
|
|
|
|
|
if (srcSel == 3 || sas == 0) {
|
|
|
|
|
auto srcAddress =
|
|
|
|
|
srcAddressLo | (static_cast<std::uint64_t>(srcAddressHi) << 32);
|
|
|
|
|
src = amdgpu::RemoteMemory{ring.vmId}.getPointer(srcAddress);
|
|
|
|
|
device->caches[ring.vmId].flush(
|
|
|
|
|
scheduler, rx::AddressRange::fromBeginSize(srcAddress, size));
|
|
|
|
|
} else {
|
|
|
|
|
src = getMmRegister(ring, srcAddressLo / sizeof(std::uint32_t));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srcSize = ~0;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
src = device->caches[ring.vmId].getGdsBuffer().getData() + srcAddressLo;
|
|
|
|
|
srcSize = ~0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
src = &data;
|
|
|
|
|
srcSize = sizeof(data);
|
|
|
|
|
saic = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("IT_DMA_DATA: unexpected srcSel {}", srcSel);
|
2024-11-13 21:53:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rx::dieIf(size > srcSize && saic == 0,
|
2025-10-04 13:23:42 +02:00
|
|
|
"IT_DMA_DATA: out of source size srcSel {}, dstSel {}, size {}",
|
2024-11-13 21:53:08 +01:00
|
|
|
srcSel, dstSel, size);
|
|
|
|
|
|
|
|
|
|
if (saic != 0) {
|
|
|
|
|
if (daic != 0 && dstSel == 0 && das == 1) {
|
|
|
|
|
std::memcpy(dst, src, sizeof(std::uint32_t));
|
|
|
|
|
} else {
|
|
|
|
|
for (std::uint32_t i = 0; i < size / sizeof(std::uint32_t); ++i) {
|
|
|
|
|
std::memcpy(std::bit_cast<std::uint32_t *>(dst) + i, src,
|
|
|
|
|
sizeof(std::uint32_t));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (daic != 0 && dstSel == 0 && das == 1) {
|
|
|
|
|
for (std::uint32_t i = 0; i < size / sizeof(std::uint32_t); ++i) {
|
|
|
|
|
std::memcpy(dst, std::bit_cast<std::uint32_t *>(src) + i,
|
|
|
|
|
sizeof(std::uint32_t));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
std::memcpy(dst, src, size);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool ComputePipe::unknownPacket(Ring &ring) {
|
|
|
|
|
auto op = rx::getBits(ring.rptr[0], 15, 8);
|
|
|
|
|
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unimplemented compute pm4 packet: {}, indirect level {}\n",
|
2024-10-15 17:35:17 +02:00
|
|
|
gnm::pm4OpcodeToString(op), ring.indirectLevel);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ComputePipe::handleNop(Ring &ring) { return true; }
|
|
|
|
|
|
|
|
|
|
std::uint32_t *ComputePipe::getMmRegister(Ring &ring, std::uint32_t dwAddress) {
|
|
|
|
|
if (dwAddress >= Registers::ComputeConfig::kMmioOffset &&
|
|
|
|
|
dwAddress <
|
|
|
|
|
Registers::ComputeConfig::kMmioOffset +
|
|
|
|
|
sizeof(Registers::ComputeConfig) / sizeof(std::uint32_t)) {
|
|
|
|
|
return ring.doorbell + (dwAddress - Registers::ComputeConfig::kMmioOffset);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unexpected memory mapped compute register address {:x}, {}",
|
|
|
|
|
dwAddress, gnm::mmio::registerName(dwAddress));
|
2024-10-15 17:35:17 +02:00
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
GraphicsPipe::GraphicsPipe(int index) : scheduler(createGfxScheduler(index)) {
|
|
|
|
|
for (auto &processorHandlers : commandHandlers) {
|
|
|
|
|
for (auto &handler : processorHandlers) {
|
|
|
|
|
handler = &GraphicsPipe::unknownPacket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
processorHandlers[gnm::IT_NOP] = &GraphicsPipe::handleNop;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-12 04:24:58 +02:00
|
|
|
auto &dataHandlers = commandHandlers[3];
|
|
|
|
|
auto &deHandlers = commandHandlers[2];
|
|
|
|
|
auto &mainHandlers = commandHandlers[1];
|
2024-09-25 15:00:55 +02:00
|
|
|
auto &ceHandlers = commandHandlers[0];
|
|
|
|
|
|
|
|
|
|
deHandlers[gnm::IT_SET_BASE] = &GraphicsPipe::setBase;
|
|
|
|
|
deHandlers[gnm::IT_CLEAR_STATE] = &GraphicsPipe::clearState;
|
|
|
|
|
|
|
|
|
|
deHandlers[gnm::IT_INDEX_BUFFER_SIZE] = &GraphicsPipe::indexBufferSize;
|
|
|
|
|
deHandlers[gnm::IT_DISPATCH_DIRECT] = &GraphicsPipe::dispatchDirect;
|
|
|
|
|
deHandlers[gnm::IT_DISPATCH_INDIRECT] = &GraphicsPipe::dispatchIndirect;
|
|
|
|
|
|
|
|
|
|
// IT_ATOMIC_GDS
|
|
|
|
|
// IT_OCCLUSION_QUERY
|
|
|
|
|
deHandlers[gnm::IT_SET_PREDICATION] = &GraphicsPipe::setPredication;
|
|
|
|
|
|
|
|
|
|
// IT_REG_RMW
|
|
|
|
|
|
|
|
|
|
// IT_COND_EXEC
|
|
|
|
|
// IT_PRED_EXEC
|
|
|
|
|
|
|
|
|
|
deHandlers[gnm::IT_DRAW_INDIRECT] = &GraphicsPipe::drawIndirect;
|
|
|
|
|
deHandlers[gnm::IT_DRAW_INDEX_INDIRECT] = &GraphicsPipe::drawIndexIndirect;
|
|
|
|
|
deHandlers[gnm::IT_INDEX_BASE] = &GraphicsPipe::indexBase;
|
|
|
|
|
deHandlers[gnm::IT_DRAW_INDEX_2] = &GraphicsPipe::drawIndex2;
|
|
|
|
|
|
2024-11-20 21:22:37 +01:00
|
|
|
mainHandlers[gnm::IT_CONTEXT_CONTROL] = &GraphicsPipe::contextControl;
|
2024-09-25 15:00:55 +02:00
|
|
|
deHandlers[gnm::IT_CONTEXT_CONTROL] = &GraphicsPipe::contextControl;
|
|
|
|
|
|
|
|
|
|
deHandlers[gnm::IT_INDEX_TYPE] = &GraphicsPipe::indexType;
|
|
|
|
|
// IT_DRAW_INDIRECT_MULTI
|
|
|
|
|
deHandlers[gnm::IT_DRAW_INDEX_AUTO] = &GraphicsPipe::drawIndexAuto;
|
|
|
|
|
deHandlers[gnm::IT_NUM_INSTANCES] = &GraphicsPipe::numInstances;
|
|
|
|
|
deHandlers[gnm::IT_DRAW_INDEX_MULTI_AUTO] = &GraphicsPipe::drawIndexMultiAuto;
|
|
|
|
|
|
2024-10-12 04:24:58 +02:00
|
|
|
mainHandlers[gnm::IT_INDIRECT_BUFFER_CNST] =
|
|
|
|
|
&GraphicsPipe::indirectBufferConst;
|
2024-09-25 15:00:55 +02:00
|
|
|
// IT_STRMOUT_BUFFER_UPDATE
|
|
|
|
|
|
|
|
|
|
deHandlers[gnm::IT_DRAW_INDEX_OFFSET_2] = &GraphicsPipe::drawIndexOffset2;
|
|
|
|
|
deHandlers[gnm::IT_DRAW_PREAMBLE] = &GraphicsPipe::drawPreamble;
|
|
|
|
|
|
|
|
|
|
deHandlers[gnm::IT_WRITE_DATA] = &GraphicsPipe::writeData;
|
|
|
|
|
deHandlers[gnm::IT_MEM_SEMAPHORE] = &GraphicsPipe::memSemaphore;
|
|
|
|
|
// IT_COPY_DW
|
|
|
|
|
deHandlers[gnm::IT_WAIT_REG_MEM] = &GraphicsPipe::waitRegMem;
|
|
|
|
|
deHandlers[gnm::IT_INDIRECT_BUFFER] = &GraphicsPipe::indirectBuffer;
|
2024-10-12 04:24:58 +02:00
|
|
|
mainHandlers[gnm::IT_INDIRECT_BUFFER] = &GraphicsPipe::indirectBuffer;
|
2024-09-25 15:00:55 +02:00
|
|
|
// IT_COPY_DATA
|
|
|
|
|
deHandlers[gnm::IT_PFP_SYNC_ME] = &GraphicsPipe::pfpSyncMe;
|
|
|
|
|
// IT_SURFACE_SYNC
|
|
|
|
|
deHandlers[gnm::IT_COND_WRITE] = &GraphicsPipe::condWrite;
|
|
|
|
|
deHandlers[gnm::IT_EVENT_WRITE] = &GraphicsPipe::eventWrite;
|
2024-10-17 00:25:43 +02:00
|
|
|
mainHandlers[gnm::IT_EVENT_WRITE_EOP] = &GraphicsPipe::eventWriteEop;
|
2024-09-25 15:00:55 +02:00
|
|
|
deHandlers[gnm::IT_EVENT_WRITE_EOP] = &GraphicsPipe::eventWriteEop;
|
|
|
|
|
deHandlers[gnm::IT_EVENT_WRITE_EOS] = &GraphicsPipe::eventWriteEos;
|
|
|
|
|
deHandlers[gnm::IT_RELEASE_MEM] = &GraphicsPipe::releaseMem;
|
2024-11-20 21:22:37 +01:00
|
|
|
deHandlers[gnm::IT_PREAMBLE_CNTL] = &GraphicsPipe::releaseMem;
|
2024-09-25 15:00:55 +02:00
|
|
|
deHandlers[gnm::IT_DMA_DATA] = &GraphicsPipe::dmaData;
|
|
|
|
|
deHandlers[gnm::IT_ACQUIRE_MEM] = &GraphicsPipe::acquireMem;
|
|
|
|
|
// IT_REWIND
|
|
|
|
|
|
|
|
|
|
// IT_LOAD_UCONFIG_REG
|
|
|
|
|
// IT_LOAD_SH_REG
|
|
|
|
|
// IT_LOAD_CONFIG_REG
|
2024-11-20 21:22:37 +01:00
|
|
|
deHandlers[gnm::IT_LOAD_UCONFIG_REG] = &GraphicsPipe::loadUConfigReg;
|
|
|
|
|
deHandlers[gnm::IT_LOAD_SH_REG] = &GraphicsPipe::loadShReg;
|
|
|
|
|
deHandlers[gnm::IT_LOAD_CONFIG_REG] = &GraphicsPipe::loadConfigReg;
|
|
|
|
|
deHandlers[gnm::IT_LOAD_CONTEXT_REG] = &GraphicsPipe::loadContextReg;
|
2024-09-25 15:00:55 +02:00
|
|
|
deHandlers[gnm::IT_SET_CONFIG_REG] = &GraphicsPipe::setConfigReg;
|
|
|
|
|
deHandlers[gnm::IT_SET_CONTEXT_REG] = &GraphicsPipe::setContextReg;
|
|
|
|
|
// IT_SET_CONTEXT_REG_INDIRECT
|
|
|
|
|
deHandlers[gnm::IT_SET_SH_REG] = &GraphicsPipe::setShReg;
|
|
|
|
|
// IT_SET_SH_REG_OFFSET
|
|
|
|
|
// IT_SET_QUEUE_REG
|
|
|
|
|
deHandlers[gnm::IT_SET_UCONFIG_REG] = &GraphicsPipe::setUConfigReg;
|
|
|
|
|
// IT_SCRATCH_RAM_WRITE
|
|
|
|
|
// IT_SCRATCH_RAM_READ
|
|
|
|
|
deHandlers[gnm::IT_INCREMENT_DE_COUNTER] = &GraphicsPipe::incrementDeCounter;
|
|
|
|
|
deHandlers[gnm::IT_WAIT_ON_CE_COUNTER] = &GraphicsPipe::waitOnCeCounter;
|
|
|
|
|
deHandlers[gnm::IT_SET_CE_DE_COUNTERS] = &GraphicsPipe::setCeDeCounters;
|
|
|
|
|
// IT_WAIT_ON_AVAIL_BUFFER
|
2024-10-12 04:24:58 +02:00
|
|
|
mainHandlers[gnm::IT_SWITCH_BUFFER] = &GraphicsPipe::switchBuffer;
|
2024-09-25 15:00:55 +02:00
|
|
|
// IT_SET_RESOURCES
|
2024-10-12 04:24:58 +02:00
|
|
|
mainHandlers[gnm::IT_MAP_QUEUES] = &GraphicsPipe::mapQueues;
|
|
|
|
|
mainHandlers[gnm::IT_UNMAP_QUEUES] = &GraphicsPipe::unmapQueues;
|
2024-09-25 15:00:55 +02:00
|
|
|
// IT_QUERY_STATUS
|
|
|
|
|
// IT_RUN_LIST
|
|
|
|
|
// IT_DISPATCH_DRAW_PREAMBLE
|
|
|
|
|
// IT_DISPATCH_DRAW
|
|
|
|
|
|
|
|
|
|
ceHandlers[gnm::IT_WAIT_ON_DE_COUNTER_DIFF] =
|
|
|
|
|
&GraphicsPipe::waitOnDeCounterDiff;
|
|
|
|
|
ceHandlers[gnm::IT_INCREMENT_CE_COUNTER] = &GraphicsPipe::incrementCeCounter;
|
|
|
|
|
ceHandlers[gnm::IT_LOAD_CONST_RAM] = &GraphicsPipe::loadConstRam;
|
|
|
|
|
ceHandlers[gnm::IT_WRITE_CONST_RAM] = &GraphicsPipe::writeConstRam;
|
|
|
|
|
ceHandlers[gnm::IT_DUMP_CONST_RAM] = &GraphicsPipe::dumpConstRam;
|
2024-11-20 21:22:37 +01:00
|
|
|
|
|
|
|
|
deHandlers[gnm::IT_WAIT_REG_MEM64] = &GraphicsPipe::waitRegMem64;
|
|
|
|
|
deHandlers[gnm::IT_LOAD_CONTEXT_REG_INDEX] =
|
|
|
|
|
&GraphicsPipe::loadContextRegIndex;
|
|
|
|
|
deHandlers[gnm::IT_LOAD_SH_REG_INDEX] = &GraphicsPipe::loadShRegIndex;
|
|
|
|
|
deHandlers[gnm::IT_LOAD_UCONFIG_REG_INDEX] =
|
|
|
|
|
&GraphicsPipe::loadUConfigRegIndex;
|
|
|
|
|
deHandlers[gnm::IT_SET_UCONFIG_REG_INDEX] = &GraphicsPipe::setUConfigRegIndex;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
void GraphicsPipe::setCeQueue(Ring ring) {
|
|
|
|
|
ring.indirectLevel = -1;
|
|
|
|
|
ceQueue = ring;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
void GraphicsPipe::setDeQueue(Ring ring, int indirectLevel) {
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::dieIf(indirectLevel > 2, "out of indirect gfx rings, {}", indirectLevel);
|
2024-10-15 17:35:17 +02:00
|
|
|
ring.indirectLevel = indirectLevel;
|
|
|
|
|
deQueues[2 - indirectLevel] = ring;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::uint32_t *GraphicsPipe::getMmRegister(std::uint32_t dwAddress) {
|
|
|
|
|
// if (dwAddress >= Registers::Config::kMmioOffset &&
|
|
|
|
|
// dwAddress < Registers::Config::kMmioOffset +
|
|
|
|
|
// sizeof(Registers::Config) / sizeof(std::uint32_t)) {
|
|
|
|
|
// return reinterpret_cast<std::uint32_t *>(&config) + (dwAddress -
|
|
|
|
|
// Registers::Config::kMmioOffset);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
if (dwAddress >= Registers::ShaderConfig::kMmioOffset &&
|
|
|
|
|
dwAddress < Registers::ShaderConfig::kMmioOffset +
|
|
|
|
|
sizeof(Registers::ShaderConfig) / sizeof(std::uint32_t)) {
|
|
|
|
|
return reinterpret_cast<std::uint32_t *>(&sh) +
|
|
|
|
|
(dwAddress - Registers::ShaderConfig::kMmioOffset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dwAddress >= Registers::UConfig::kMmioOffset &&
|
|
|
|
|
dwAddress < Registers::UConfig::kMmioOffset +
|
|
|
|
|
sizeof(Registers::UConfig) / sizeof(std::uint32_t)) {
|
|
|
|
|
return reinterpret_cast<std::uint32_t *>(&uConfig) +
|
|
|
|
|
(dwAddress - Registers::UConfig::kMmioOffset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dwAddress >= Registers::Context::kMmioOffset &&
|
|
|
|
|
dwAddress < Registers::Context::kMmioOffset +
|
|
|
|
|
sizeof(Registers::Context) / sizeof(std::uint32_t)) {
|
|
|
|
|
return reinterpret_cast<std::uint32_t *>(&context) +
|
|
|
|
|
(dwAddress - Registers::Context::kMmioOffset);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unexpected memory mapped register address {:x}, {}", dwAddress,
|
2024-09-25 15:00:55 +02:00
|
|
|
gnm::mmio::registerName(dwAddress));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GraphicsPipe::processAllRings() {
|
|
|
|
|
bool allProcessed = true;
|
|
|
|
|
|
|
|
|
|
if (ceQueue.rptr != ceQueue.wptr) {
|
|
|
|
|
processRing(ceQueue);
|
|
|
|
|
|
|
|
|
|
if (ceQueue.rptr != ceQueue.wptr) {
|
|
|
|
|
allProcessed = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
for (auto &ring : deQueues) {
|
|
|
|
|
if (ring.rptr == ring.wptr) {
|
2024-09-29 20:37:12 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
processRing(ring);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
if (ring.rptr != ring.wptr) {
|
2024-09-25 15:00:55 +02:00
|
|
|
allProcessed = false;
|
2024-10-22 18:04:32 +02:00
|
|
|
|
|
|
|
|
for (auto &delayedRing : delayedRings) {
|
|
|
|
|
if (delayedRing.rptr != delayedRing.wptr) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delayedRing = ring;
|
|
|
|
|
ring.rptr = ring.wptr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-25 15:00:55 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-22 18:04:32 +02:00
|
|
|
if (allProcessed) {
|
|
|
|
|
for (auto &ring : delayedRings) {
|
|
|
|
|
if (ring.rptr == ring.wptr) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
processRing(ring);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-25 15:00:55 +02:00
|
|
|
return allProcessed;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
void GraphicsPipe::processRing(Ring &ring) {
|
2024-11-13 21:53:08 +01:00
|
|
|
int cp = 1;
|
2024-10-15 17:35:17 +02:00
|
|
|
if (ring.indirectLevel < 0) {
|
2024-09-25 15:00:55 +02:00
|
|
|
cp = 0;
|
2024-10-12 04:24:58 +02:00
|
|
|
} else {
|
2024-10-15 17:35:17 +02:00
|
|
|
cp = ring.indirectLevel + 1;
|
2024-11-13 21:53:08 +01:00
|
|
|
|
|
|
|
|
if (ring.indirectLevel == 2) {
|
|
|
|
|
cp = 2;
|
|
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
while (ring.rptr != ring.wptr) {
|
|
|
|
|
if (ring.rptr >= ring.base + ring.size) {
|
|
|
|
|
ring.rptr = ring.base;
|
2024-10-12 04:24:58 +02:00
|
|
|
continue;
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
auto header = *ring.rptr;
|
2024-09-25 15:00:55 +02:00
|
|
|
auto type = rx::getBits(header, 31, 30);
|
|
|
|
|
|
|
|
|
|
if (type == 3) {
|
|
|
|
|
auto op = rx::getBits(header, 15, 8);
|
|
|
|
|
auto len = rx::getBits(header, 29, 16) + 2;
|
|
|
|
|
|
2024-10-12 04:24:58 +02:00
|
|
|
// if (auto str = gnm::pm4OpcodeToString(op)) {
|
2024-10-15 17:35:17 +02:00
|
|
|
// std::println(stderr, "queue {}: {}", ring.indirectLevel, str);
|
2024-10-12 04:24:58 +02:00
|
|
|
// } else {
|
2024-10-15 17:35:17 +02:00
|
|
|
// std::println(stderr, "queue {}: {:x}", ring.indirectLevel, op);
|
2024-10-12 04:24:58 +02:00
|
|
|
// }
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
if (op == gnm::IT_COND_EXEC) {
|
2024-11-20 21:22:37 +01:00
|
|
|
std::println("unimplemented COND_EXEC");
|
|
|
|
|
} else {
|
|
|
|
|
auto handler = commandHandlers[cp][op];
|
|
|
|
|
if (!(this->*handler)(ring)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-13 21:53:08 +01:00
|
|
|
ring.rptr +=
|
|
|
|
|
std::min<std::uint32_t>(ring.size - (ring.rptr - ring.base), len);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
if (op == gnm::IT_INDIRECT_BUFFER || op == gnm::IT_INDIRECT_BUFFER_CNST) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type == 2) {
|
2024-10-15 17:35:17 +02:00
|
|
|
++ring.rptr;
|
2024-09-25 15:00:55 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unexpected pm4 packet type {}, ring {}, header {}, rptr {}, wptr "
|
|
|
|
|
"{}, base {}",
|
|
|
|
|
type, ring.indirectLevel, header, (void *)ring.rptr,
|
|
|
|
|
(void *)ring.wptr, ring.base);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::handleNop(Ring &ring) { return true; }
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::setBase(Ring &ring) {
|
|
|
|
|
auto baseIndex = ring.rptr[1] & 0xf;
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
switch (baseIndex) {
|
|
|
|
|
case 0: {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto address0 = ring.rptr[2] & ~3;
|
|
|
|
|
auto address1 = ring.rptr[3] & ((1 << 16) - 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
displayListPatchBase =
|
|
|
|
|
address0 | (static_cast<std::uint64_t>(address1) << 32);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 1: {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto address0 = ring.rptr[2] & ~3;
|
|
|
|
|
auto address1 = ring.rptr[3] & ((1 << 16) - 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
drawIndexIndirPatchBase =
|
|
|
|
|
address0 | (static_cast<std::uint64_t>(address1) << 32);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 2: {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto cs1Index = ring.rptr[2] & ((1 << 16) - 1);
|
|
|
|
|
auto cs2Index = ring.rptr[3] & ((1 << 16) - 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
gdsPartitionBases[0] = cs1Index;
|
|
|
|
|
gdsPartitionBases[1] = cs2Index;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 3: {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto cs1Index = ring.rptr[2] & ((1 << 16) - 1);
|
|
|
|
|
auto cs2Index = ring.rptr[3] & ((1 << 16) - 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
cePartitionBases[0] = cs1Index;
|
|
|
|
|
cePartitionBases[1] = cs2Index;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("pm4: unknown SET_BASE index {}", baseIndex);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::clearState(Ring &ring) {
|
2024-09-25 20:50:07 +02:00
|
|
|
auto paScClipRectRule = context.paScClipRectRule.value;
|
|
|
|
|
auto cbTargetMask = context.cbTargetMask.raw;
|
|
|
|
|
auto cbShaderMask = context.cbShaderMask.raw;
|
|
|
|
|
auto vgtMaxVtxIndx = context.vgtMaxVtxIndx.value;
|
|
|
|
|
auto vgtMinVtxIndx = context.vgtMinVtxIndx.value;
|
|
|
|
|
auto vgtIndxOffset = context.vgtIndxOffset.value;
|
|
|
|
|
auto paScAaMaskX0Y0_X1Y0 = context.paScAaMaskX0Y0_X1Y0.value;
|
|
|
|
|
auto paScAaMaskX0Y1_X1Y1 = context.paScAaMaskX0Y1_X1Y1.value;
|
|
|
|
|
|
2024-09-25 15:00:55 +02:00
|
|
|
context = Registers::Context::Default;
|
2024-09-25 20:50:07 +02:00
|
|
|
|
|
|
|
|
context.paScClipRectRule.value = paScClipRectRule;
|
|
|
|
|
context.cbTargetMask.raw = cbTargetMask;
|
|
|
|
|
context.cbShaderMask.raw = cbShaderMask;
|
|
|
|
|
context.vgtMaxVtxIndx.value = vgtMaxVtxIndx;
|
|
|
|
|
context.vgtMinVtxIndx.value = vgtMinVtxIndx;
|
|
|
|
|
context.vgtIndxOffset.value = vgtIndxOffset;
|
|
|
|
|
context.paScAaMaskX0Y0_X1Y0.value = paScAaMaskX0Y0_X1Y0;
|
|
|
|
|
context.paScAaMaskX0Y1_X1Y1.value = paScAaMaskX0Y1_X1Y1;
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::contextControl(Ring &ring) { return true; }
|
|
|
|
|
bool GraphicsPipe::acquireMem(Ring &ring) { return true; }
|
|
|
|
|
bool GraphicsPipe::releaseMem(Ring &ring) {
|
|
|
|
|
auto eventCntl = ring.rptr[1];
|
|
|
|
|
auto dataCntl = ring.rptr[2];
|
|
|
|
|
auto addressLo = ring.rptr[3] & ~3;
|
|
|
|
|
auto addressHi = ring.rptr[4] & ((1 << 16) - 1);
|
|
|
|
|
auto dataLo = ring.rptr[5];
|
|
|
|
|
auto dataHi = ring.rptr[6];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
auto eventIndex = rx::getBits(eventCntl, 11, 8);
|
|
|
|
|
auto eventType = rx::getBits(eventCntl, 5, 0);
|
|
|
|
|
auto dataSel = rx::getBits(dataCntl, 31, 29);
|
|
|
|
|
auto intSel = rx::getBits(dataCntl, 25, 24);
|
|
|
|
|
|
|
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
auto pointer = RemoteMemory{ring.vmId}.getPointer<std::uint64_t>(address);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
context.vgtEventInitiator = eventType;
|
|
|
|
|
|
|
|
|
|
switch (dataSel) {
|
|
|
|
|
case 0: // none
|
|
|
|
|
break;
|
|
|
|
|
case 1: // 32 bit, low
|
|
|
|
|
*reinterpret_cast<std::uint32_t *>(pointer) = dataLo;
|
|
|
|
|
break;
|
|
|
|
|
case 2: // 64 bit
|
|
|
|
|
*pointer = dataLo | (static_cast<std::uint64_t>(dataHi) << 32);
|
|
|
|
|
break;
|
|
|
|
|
case 3: // 64 bit, global GPU clock
|
|
|
|
|
*pointer = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
|
|
|
std::chrono::system_clock::now().time_since_epoch())
|
|
|
|
|
.count();
|
|
|
|
|
break;
|
|
|
|
|
case 4: // 64 bit, perf counter
|
|
|
|
|
*pointer = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
|
|
|
std::chrono::steady_clock::now().time_since_epoch())
|
|
|
|
|
.count();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2024-11-20 21:22:37 +01:00
|
|
|
std::println(stderr,
|
|
|
|
|
"unimplemented event release mem data {:#x}, address {}, "
|
|
|
|
|
"dataLo {:x}, dataHi {:x}",
|
|
|
|
|
dataSel, address, dataLo, dataHi);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::drawPreamble(Ring &ring) { return true; }
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::indexBufferSize(Ring &ring) {
|
|
|
|
|
vgtIndexBufferSize = ring.rptr[1];
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::dispatchDirect(Ring &ring) {
|
|
|
|
|
auto dimX = ring.rptr[1];
|
|
|
|
|
auto dimY = ring.rptr[2];
|
|
|
|
|
auto dimZ = ring.rptr[3];
|
|
|
|
|
auto dispatchInitiator = ring.rptr[4];
|
2024-09-25 15:00:55 +02:00
|
|
|
sh.compute.computeDispatchInitiator = dispatchInitiator;
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
amdgpu::dispatch(device->caches[ring.vmId], scheduler, sh.compute, dimX, dimY,
|
|
|
|
|
dimZ);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::dispatchIndirect(Ring &ring) {
|
|
|
|
|
auto offset = ring.rptr[1];
|
|
|
|
|
auto dispatchInitiator = ring.rptr[2];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
sh.compute.computeDispatchInitiator = dispatchInitiator;
|
2024-10-15 17:35:17 +02:00
|
|
|
auto buffer = RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(
|
2024-09-25 15:00:55 +02:00
|
|
|
drawIndexIndirPatchBase + offset);
|
|
|
|
|
|
|
|
|
|
auto dimX = buffer[0];
|
|
|
|
|
auto dimY = buffer[1];
|
|
|
|
|
auto dimZ = buffer[2];
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
amdgpu::dispatch(device->caches[ring.vmId], scheduler, sh.compute, dimX, dimY,
|
|
|
|
|
dimZ);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::setPredication(Ring &ring) {
|
|
|
|
|
auto startAddressLo = ring.rptr[1] & ~0xf;
|
|
|
|
|
auto predProperties = ring.rptr[2];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
auto startAddressHi = rx::getBits(predProperties, 15, 0);
|
|
|
|
|
auto predBool = rx::getBit(predProperties, 8);
|
|
|
|
|
auto hint = rx::getBit(predProperties, 12);
|
|
|
|
|
auto predOp = rx::getBits(predProperties, 18, 16);
|
|
|
|
|
auto cont = rx::getBit(predProperties, 31);
|
|
|
|
|
|
|
|
|
|
switch (predOp) {
|
|
|
|
|
case 0: // clear predicate
|
|
|
|
|
case 1: // set ZPass predicate
|
|
|
|
|
case 2: // set PrimCount predicate
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::drawIndirect(Ring &ring) {
|
|
|
|
|
auto dataOffset = ring.rptr[1];
|
|
|
|
|
auto baseVtxLoc = ring.rptr[2] & ((1 << 16) - 1);
|
|
|
|
|
auto startInstLoc = ring.rptr[3] & ((1 << 16) - 1);
|
|
|
|
|
auto drawInitiator = ring.rptr[4];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
context.vgtDrawInitiator = drawInitiator;
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
auto buffer = RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(
|
2024-09-25 15:00:55 +02:00
|
|
|
drawIndexIndirPatchBase + dataOffset);
|
|
|
|
|
|
|
|
|
|
std::uint32_t vertexCountPerInstance = buffer[0];
|
|
|
|
|
std::uint32_t instanceCount = buffer[1];
|
|
|
|
|
std::uint32_t startVertexLocation = buffer[2];
|
|
|
|
|
std::uint32_t startInstanceLocation = buffer[3];
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
draw(*this, ring.vmId, startVertexLocation, vertexCountPerInstance,
|
2024-10-06 03:06:44 +02:00
|
|
|
startInstanceLocation, instanceCount, 0, 0, 0);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::drawIndexIndirect(Ring &ring) {
|
|
|
|
|
auto dataOffset = ring.rptr[1];
|
|
|
|
|
auto baseVtxLoc = ring.rptr[2] & ((1 << 16) - 1);
|
|
|
|
|
auto drawInitiator = ring.rptr[3];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
auto buffer = RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(
|
2024-09-25 15:00:55 +02:00
|
|
|
drawIndexIndirPatchBase + dataOffset);
|
|
|
|
|
|
|
|
|
|
context.vgtDrawInitiator = drawInitiator;
|
|
|
|
|
|
|
|
|
|
std::uint32_t indexCountPerInstance = buffer[0];
|
|
|
|
|
std::uint32_t instanceCount = buffer[1];
|
|
|
|
|
std::uint32_t startIndexLocation = buffer[2];
|
|
|
|
|
std::uint32_t baseVertexLocation = buffer[3];
|
|
|
|
|
std::uint32_t startInstanceLocation = buffer[4];
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
draw(*this, ring.vmId, baseVertexLocation, indexCountPerInstance,
|
2024-10-06 03:06:44 +02:00
|
|
|
startInstanceLocation, instanceCount, vgtIndexBase, startIndexLocation,
|
2024-09-29 20:37:12 +02:00
|
|
|
indexCountPerInstance);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::indexBase(Ring &ring) {
|
|
|
|
|
auto addressLo = ring.rptr[1] & ~1;
|
|
|
|
|
auto addressHi = ring.rptr[2] & ((1 << 16) - 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
vgtIndexBase = address;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::drawIndex2(Ring &ring) {
|
|
|
|
|
auto maxSize = ring.rptr[1];
|
|
|
|
|
auto indexBaseLo = ring.rptr[2] & ~1;
|
|
|
|
|
auto indexBaseHi = ring.rptr[3] & ((1 << 16) - 1);
|
|
|
|
|
auto indexCount = ring.rptr[4];
|
|
|
|
|
auto drawInitiator = ring.rptr[5];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
context.vgtDrawInitiator = drawInitiator;
|
|
|
|
|
uConfig.vgtNumIndices = indexCount;
|
|
|
|
|
|
2024-10-06 12:03:30 +02:00
|
|
|
auto indexBase =
|
|
|
|
|
indexBaseLo | (static_cast<std::uint64_t>(indexBaseHi) << 32);
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
draw(*this, ring.vmId, 0, indexCount, 0, uConfig.vgtNumInstances, indexBase,
|
2024-10-06 12:03:30 +02:00
|
|
|
0, maxSize);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::indexType(Ring &ring) {
|
|
|
|
|
uConfig.vgtIndexType = static_cast<gnm::IndexType>(ring.rptr[1] & 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::drawIndexAuto(Ring &ring) {
|
|
|
|
|
auto indexCount = ring.rptr[1];
|
|
|
|
|
auto drawInitiator = ring.rptr[2];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
uConfig.vgtNumIndices = indexCount;
|
|
|
|
|
context.vgtDrawInitiator = drawInitiator;
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
draw(*this, ring.vmId, 0, indexCount, 0, uConfig.vgtNumInstances, 0, 0, 0);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::numInstances(Ring &ring) {
|
2024-11-13 21:53:08 +01:00
|
|
|
uConfig.vgtNumInstances = std::max(std::uint32_t(ring.rptr[1]), 1u);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::drawIndexMultiAuto(Ring &ring) {
|
|
|
|
|
auto primCount = ring.rptr[1];
|
|
|
|
|
auto drawInitiator = ring.rptr[2];
|
|
|
|
|
auto control = ring.rptr[3];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
auto indexOffset = rx::getBits(control, 15, 0);
|
|
|
|
|
auto primType = rx::getBits(control, 20, 16);
|
|
|
|
|
auto indexCount = rx::getBits(control, 31, 21);
|
|
|
|
|
|
|
|
|
|
context.vgtDrawInitiator = drawInitiator;
|
|
|
|
|
uConfig.vgtPrimitiveType = static_cast<gnm::PrimitiveType>(primType);
|
|
|
|
|
uConfig.vgtNumIndices = indexCount;
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
draw(*this, ring.vmId, 0, primCount, 0, uConfig.vgtNumInstances, vgtIndexBase,
|
|
|
|
|
indexOffset, indexCount);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::drawIndexOffset2(Ring &ring) {
|
|
|
|
|
auto maxSize = ring.rptr[1];
|
|
|
|
|
auto indexOffset = ring.rptr[2];
|
|
|
|
|
auto indexCount = ring.rptr[3];
|
|
|
|
|
auto drawInitiator = ring.rptr[4];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
context.vgtDrawInitiator = drawInitiator;
|
2024-10-15 17:35:17 +02:00
|
|
|
draw(*this, ring.vmId, 0, indexCount, 0, uConfig.vgtNumInstances,
|
2024-10-06 03:06:44 +02:00
|
|
|
vgtIndexBase, indexOffset, maxSize);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::writeData(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16) - 1;
|
|
|
|
|
auto control = ring.rptr[1];
|
|
|
|
|
auto dstAddressLo = ring.rptr[2];
|
|
|
|
|
auto dstAddressHi = ring.rptr[3];
|
|
|
|
|
auto data = ring.rptr + 4;
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
auto engineSel = rx::getBits(control, 31, 30);
|
|
|
|
|
auto wrConfirm = rx::getBit(control, 20);
|
|
|
|
|
auto wrOneAddress = rx::getBit(control, 16);
|
|
|
|
|
auto dstSel = rx::getBits(control, 11, 8);
|
|
|
|
|
|
|
|
|
|
std::uint32_t *dstPointer = nullptr;
|
|
|
|
|
|
|
|
|
|
switch (dstSel) {
|
|
|
|
|
case 0: // memory mapped register
|
|
|
|
|
dstPointer = getMmRegister(dstAddressLo & ((1 << 16) - 1));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: // memory sync
|
2024-10-04 22:52:37 +02:00
|
|
|
case 2: // TC L2
|
2024-09-25 15:00:55 +02:00
|
|
|
case 5: { // memory async
|
|
|
|
|
auto address =
|
|
|
|
|
(dstAddressLo & ~3) | (static_cast<std::uint64_t>(dstAddressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
dstPointer = RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
2024-09-25 15:00:55 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unimplemented write data, dst sel = {:#x}", dstSel);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wrOneAddress) {
|
|
|
|
|
for (std::uint32_t i = 0; i < len; ++i) {
|
|
|
|
|
*dstPointer = data[i];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-04-05 21:50:45 +02:00
|
|
|
std::memcpy(dstPointer, const_cast<std::uint32_t *>(data),
|
|
|
|
|
len * sizeof(std::uint32_t));
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::memSemaphore(Ring &ring) {
|
2024-09-25 15:00:55 +02:00
|
|
|
// FIXME
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::waitRegMem(Ring &ring) {
|
|
|
|
|
auto engine = rx::getBit(ring.rptr[1], 8);
|
|
|
|
|
auto memSpace = rx::getBit(ring.rptr[1], 4);
|
|
|
|
|
auto function = rx::getBits(ring.rptr[1], 2, 0);
|
|
|
|
|
auto pollAddressLo = ring.rptr[2];
|
|
|
|
|
auto pollAddressHi = ring.rptr[3] & ((1 << 16) - 1);
|
|
|
|
|
auto reference = ring.rptr[4];
|
|
|
|
|
auto mask = ring.rptr[5];
|
|
|
|
|
auto pollInterval = ring.rptr[6];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
std::uint32_t pollData;
|
|
|
|
|
|
|
|
|
|
if (memSpace == 0) {
|
|
|
|
|
pollData = *getMmRegister(pollAddressLo & ((1 << 16) - 1));
|
|
|
|
|
} else {
|
|
|
|
|
auto pollAddress = (pollAddressLo & ~3) |
|
|
|
|
|
(static_cast<std::uint64_t>(pollAddressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
pollData = *RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(pollAddress);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return compare(function, pollData, mask, reference);
|
|
|
|
|
}
|
2024-10-12 04:24:58 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::indirectBufferConst(Ring &ring) {
|
|
|
|
|
rx::dieIf(ring.indirectLevel < 0, "unexpected indirect buffer from CP");
|
2024-10-12 04:24:58 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
auto addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
auto addressHi = ring.rptr[2] & ((1 << 8) - 1);
|
|
|
|
|
int vmId = ring.rptr[3] >> 24;
|
|
|
|
|
auto ibSize = ring.rptr[3] & ((1 << 20) - 1);
|
2024-10-12 04:24:58 +02:00
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
if (ring.indirectLevel != 0) {
|
|
|
|
|
vmId = ring.vmId;
|
2024-10-12 04:24:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto rptr = RemoteMemory{vmId}.getPointer<std::uint32_t>(address);
|
2024-10-15 17:35:17 +02:00
|
|
|
setCeQueue(Ring::createFromRange(vmId, rptr, ibSize));
|
2024-10-12 04:24:58 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::indirectBuffer(Ring &ring) {
|
|
|
|
|
rx::dieIf(ring.indirectLevel < 0, "unexpected indirect buffer from CP");
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
auto addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
auto addressHi = ring.rptr[2] & ((1 << 8) - 1);
|
|
|
|
|
int vmId = ring.rptr[3] >> 24;
|
|
|
|
|
auto ibSize = ring.rptr[3] & ((1 << 20) - 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
if (ring.indirectLevel != 0) {
|
|
|
|
|
vmId = ring.vmId;
|
2024-10-12 04:24:58 +02:00
|
|
|
}
|
|
|
|
|
auto rptr = RemoteMemory{vmId}.getPointer<std::uint32_t>(address);
|
2024-10-15 17:35:17 +02:00
|
|
|
setDeQueue(Ring::createFromRange(vmId, rptr, ibSize), ring.indirectLevel + 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::pfpSyncMe(Ring &ring) {
|
2024-09-25 15:00:55 +02:00
|
|
|
// TODO
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::condWrite(Ring &ring) {
|
|
|
|
|
auto writeSpace = rx::getBit(ring.rptr[1], 8);
|
|
|
|
|
auto pollSpace = rx::getBit(ring.rptr[1], 4);
|
|
|
|
|
auto function = rx::getBits(ring.rptr[1], 2, 0);
|
|
|
|
|
auto pollAddressLo = ring.rptr[2];
|
|
|
|
|
auto pollAddressHi = ring.rptr[3] & ((1 << 16) - 1);
|
|
|
|
|
auto reference = ring.rptr[4];
|
|
|
|
|
auto mask = ring.rptr[5];
|
|
|
|
|
auto writeAddressLo = ring.rptr[6];
|
|
|
|
|
auto writeAddressHi = ring.rptr[7] & ((1 << 16) - 1);
|
|
|
|
|
auto writeData = ring.rptr[8];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
std::uint32_t pollData;
|
|
|
|
|
|
|
|
|
|
if (pollSpace == 0) {
|
|
|
|
|
pollData = *getMmRegister(pollAddressLo & ((1 << 16) - 1));
|
|
|
|
|
} else {
|
|
|
|
|
auto pollAddress = (pollAddressLo & ~3) |
|
|
|
|
|
(static_cast<std::uint64_t>(pollAddressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
pollData = *RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(pollAddress);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (compare(function, pollData, mask, reference)) {
|
|
|
|
|
if (writeSpace == 0) {
|
|
|
|
|
*getMmRegister(writeAddressLo & ((1 << 16) - 1)) = writeData;
|
|
|
|
|
} else {
|
|
|
|
|
auto writeAddress = (writeAddressLo & ~3) |
|
|
|
|
|
(static_cast<std::uint64_t>(writeAddressHi) << 32);
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
*RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(writeAddress) =
|
2024-09-25 15:00:55 +02:00
|
|
|
writeData;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::eventWrite(Ring &ring) {
|
2024-09-25 15:00:55 +02:00
|
|
|
enum {
|
|
|
|
|
kEventZPassDone = 1,
|
|
|
|
|
kEventSamplePipelineStat = 2,
|
|
|
|
|
kEventSampleStreamOutStat = 3,
|
|
|
|
|
kEventPartialFlush = 4,
|
|
|
|
|
};
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
auto eventCntl = ring.rptr[1];
|
2024-09-25 15:00:55 +02:00
|
|
|
auto invL2 = rx::getBit(eventCntl, 20);
|
|
|
|
|
auto eventIndex = rx::getBits(eventCntl, 11, 8);
|
|
|
|
|
auto eventType = rx::getBits(eventCntl, 5, 0);
|
|
|
|
|
|
|
|
|
|
context.vgtEventInitiator = eventType;
|
|
|
|
|
|
|
|
|
|
if (eventIndex == kEventZPassDone || eventIndex == kEventSamplePipelineStat ||
|
|
|
|
|
eventIndex == kEventSampleStreamOutStat) {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto addressLo = ring.rptr[2] & ~7;
|
|
|
|
|
auto addressHi = ring.rptr[3] & ((1 << 16) - 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unimplemented event write, event index {:#x}, address {:x}",
|
2024-09-25 15:00:55 +02:00
|
|
|
eventIndex, address);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::eventWriteEop(Ring &ring) {
|
|
|
|
|
auto eventCntl = ring.rptr[1];
|
2024-10-17 00:25:43 +02:00
|
|
|
auto addressLo = ring.rptr[2];
|
2024-10-15 17:35:17 +02:00
|
|
|
auto dataCntl = ring.rptr[3];
|
|
|
|
|
auto dataLo = ring.rptr[4];
|
|
|
|
|
auto dataHi = ring.rptr[5];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
auto invL2 = rx::getBit(eventCntl, 20);
|
|
|
|
|
auto eventIndex = rx::getBits(eventCntl, 11, 8);
|
|
|
|
|
auto eventType = rx::getBits(eventCntl, 5, 0);
|
|
|
|
|
auto dataSel = rx::getBits(dataCntl, 31, 29);
|
|
|
|
|
auto intSel = rx::getBits(dataCntl, 25, 24);
|
|
|
|
|
auto addressHi = rx::getBits(dataCntl, 15, 0);
|
|
|
|
|
|
|
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
auto pointer = RemoteMemory{ring.vmId}.getPointer<std::uint64_t>(address);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
context.vgtEventInitiator = eventType;
|
|
|
|
|
|
2024-10-17 00:25:43 +02:00
|
|
|
if (pointer != nullptr) {
|
|
|
|
|
switch (dataSel) {
|
|
|
|
|
case 0: // none
|
|
|
|
|
break;
|
|
|
|
|
case 1: // 32 bit, low
|
|
|
|
|
*reinterpret_cast<std::uint32_t *>(pointer) = dataLo;
|
|
|
|
|
break;
|
|
|
|
|
case 2: // 64 bit
|
|
|
|
|
*pointer = dataLo | (static_cast<std::uint64_t>(dataHi) << 32);
|
|
|
|
|
break;
|
|
|
|
|
case 3: // 64 bit, global GPU clock
|
|
|
|
|
*pointer = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
|
|
|
std::chrono::system_clock::now().time_since_epoch())
|
|
|
|
|
.count();
|
|
|
|
|
break;
|
|
|
|
|
case 4: // 64 bit, perf counter
|
|
|
|
|
*pointer = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
|
|
|
std::chrono::steady_clock::now().time_since_epoch())
|
|
|
|
|
.count();
|
|
|
|
|
break;
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-17 00:25:43 +02:00
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unimplemented event write eop data {:x}", dataSel);
|
2024-10-17 00:25:43 +02:00
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 00:25:43 +02:00
|
|
|
if (intSel != 0) {
|
2025-10-10 18:56:11 +02:00
|
|
|
orbis::g_context->deviceEventEmitter->emit(
|
2024-11-25 01:06:33 +01:00
|
|
|
orbis::kEvFiltGraphicsCore,
|
|
|
|
|
[=](orbis::KNote *note) -> std::optional<std::int64_t> {
|
|
|
|
|
if (note->event.ident == kGcEventGfxEop) {
|
|
|
|
|
return dataLo | (static_cast<std::uint64_t>(dataHi) << 32);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (note->event.ident == kGcEventGfxEop + 1) { // hp3d
|
|
|
|
|
return dataLo | (static_cast<std::uint64_t>(dataHi) << 32);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
});
|
2024-10-12 04:24:58 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 02:42:49 +02:00
|
|
|
if (intSel == 2 && dataSel == 2) {
|
2024-10-16 04:11:45 +02:00
|
|
|
std::optional<EopFlipRequest> request;
|
2024-10-17 00:25:43 +02:00
|
|
|
int index = -1;
|
2024-10-16 04:11:45 +02:00
|
|
|
{
|
|
|
|
|
std::lock_guard lock(eopFlipMtx);
|
|
|
|
|
|
2024-10-17 00:25:43 +02:00
|
|
|
auto data = dataLo | (static_cast<std::uint64_t>(dataHi) << 32);
|
|
|
|
|
for (auto &request : std::span(eopFlipRequests, eopFlipRequestCount)) {
|
|
|
|
|
if (request.eopValue == data) {
|
|
|
|
|
index = &request - eopFlipRequests;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (index >= 0) {
|
2024-10-16 04:11:45 +02:00
|
|
|
request = eopFlipRequests[index];
|
2024-10-17 00:25:43 +02:00
|
|
|
|
|
|
|
|
if (index + 1 != eopFlipRequestCount) {
|
|
|
|
|
std::swap(eopFlipRequests[index],
|
|
|
|
|
eopFlipRequests[eopFlipRequestCount - 1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
--eopFlipRequestCount;
|
2024-10-16 04:11:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (request) {
|
|
|
|
|
device->flip(request->pid, request->bufferIndex, request->arg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::eventWriteEos(Ring &ring) {
|
|
|
|
|
auto eventCntl = ring.rptr[1];
|
|
|
|
|
auto addressLo = ring.rptr[2] & ~3;
|
|
|
|
|
auto cmdInfo = ring.rptr[3];
|
|
|
|
|
auto dataInfo = ring.rptr[4];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
auto eventIndex = rx::getBits(eventCntl, 11, 8);
|
|
|
|
|
auto eventType = rx::getBits(eventCntl, 5, 0);
|
|
|
|
|
auto cmd = rx::getBits(cmdInfo, 31, 29);
|
|
|
|
|
auto addressHi = rx::getBits(cmdInfo, 15, 0);
|
|
|
|
|
|
|
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
auto pointer = RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
context.vgtEventInitiator = eventType;
|
2024-10-15 17:35:17 +02:00
|
|
|
auto &cache = device->caches[ring.vmId];
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case 1: { // store GDS data to memory
|
|
|
|
|
auto sizeDw = rx::getBits(dataInfo, 31, 16);
|
|
|
|
|
auto gdsIndexDw = rx::getBits(dataInfo, 15, 0);
|
2024-11-13 21:53:08 +01:00
|
|
|
std::println(stderr, "event write eos: gds data {:x}-{:x}", gdsIndexDw,
|
2024-09-30 20:44:05 +02:00
|
|
|
gdsIndexDw + sizeDw);
|
|
|
|
|
auto size = sizeof(std::uint32_t) * sizeDw;
|
|
|
|
|
|
|
|
|
|
auto gds = cache.getGdsBuffer().getData();
|
2024-10-09 13:59:13 +02:00
|
|
|
cache.invalidate(scheduler, rx::AddressRange::fromBeginSize(address, size));
|
2024-09-30 20:44:05 +02:00
|
|
|
std::memcpy(pointer, gds + gdsIndexDw * sizeof(std::uint32_t), size);
|
2024-09-25 15:00:55 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 2: // after GDS writes confirm, store 32 bit DATA to memory as fence
|
2024-10-09 13:59:13 +02:00
|
|
|
cache.invalidate(scheduler, rx::AddressRange::fromBeginSize(
|
|
|
|
|
address, sizeof(std::uint32_t)));
|
2024-09-25 15:00:55 +02:00
|
|
|
*pointer = dataInfo;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unexpected event write eos command: {:#x}", cmd);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::dmaData(Ring &ring) {
|
|
|
|
|
auto control = ring.rptr[1];
|
|
|
|
|
auto srcAddressLo = ring.rptr[2];
|
2024-09-30 21:43:21 +02:00
|
|
|
auto data = srcAddressLo;
|
2024-10-15 17:35:17 +02:00
|
|
|
auto srcAddressHi = ring.rptr[3];
|
|
|
|
|
auto dstAddressLo = ring.rptr[4];
|
|
|
|
|
auto dstAddressHi = ring.rptr[5];
|
|
|
|
|
auto cmdSize = ring.rptr[6];
|
2024-09-30 21:43:21 +02:00
|
|
|
auto size = rx::getBits(cmdSize, 20, 0);
|
|
|
|
|
|
|
|
|
|
auto engine = rx::getBit(control, 0);
|
|
|
|
|
auto srcVolatile = rx::getBit(control, 15);
|
|
|
|
|
|
|
|
|
|
// 0 - dstAddress using das
|
|
|
|
|
// 1 - gds
|
|
|
|
|
// 3 - dstAddress using L2
|
|
|
|
|
auto dstSel = rx::getBits(control, 21, 20);
|
|
|
|
|
|
|
|
|
|
// 0 - LRU
|
|
|
|
|
// 1 - Stream
|
|
|
|
|
// 2 - Bypass
|
|
|
|
|
auto dstCachePolicy = rx::getBits(control, 26, 25);
|
|
|
|
|
|
|
|
|
|
auto dstVolatile = rx::getBit(control, 27);
|
|
|
|
|
|
|
|
|
|
// 0 - srcAddress using sas
|
|
|
|
|
// 1 - gds
|
|
|
|
|
// 2 - data
|
|
|
|
|
// 3 - srcAddress using L2
|
|
|
|
|
auto srcSel = rx::getBits(control, 30, 29);
|
|
|
|
|
|
|
|
|
|
auto cpSync = rx::getBit(control, 31);
|
|
|
|
|
|
|
|
|
|
auto dataDisWc = rx::getBit(cmdSize, 21);
|
|
|
|
|
|
|
|
|
|
// 0 - none
|
|
|
|
|
// 1 - 8 in 16
|
|
|
|
|
// 2 - 8 in 32
|
|
|
|
|
// 3 - 8 in 64
|
|
|
|
|
auto dstSwap = rx::getBits(cmdSize, 25, 24);
|
|
|
|
|
|
|
|
|
|
// 0 - memory
|
|
|
|
|
// 1 - register
|
|
|
|
|
auto sas = rx::getBit(cmdSize, 26);
|
|
|
|
|
|
|
|
|
|
// 0 - memory
|
|
|
|
|
// 1 - register
|
|
|
|
|
auto das = rx::getBit(cmdSize, 27);
|
|
|
|
|
|
|
|
|
|
auto saic = rx::getBit(cmdSize, 28);
|
|
|
|
|
auto daic = rx::getBit(cmdSize, 29);
|
|
|
|
|
auto rawWait = rx::getBit(cmdSize, 30);
|
|
|
|
|
|
|
|
|
|
void *dst = nullptr;
|
|
|
|
|
switch (dstSel) {
|
|
|
|
|
case 3:
|
|
|
|
|
case 0:
|
|
|
|
|
if (dstSel == 3 || das == 0) {
|
|
|
|
|
auto dstAddress =
|
|
|
|
|
dstAddressLo | (static_cast<std::uint64_t>(dstAddressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
dst = amdgpu::RemoteMemory{ring.vmId}.getPointer(dstAddress);
|
|
|
|
|
device->caches[ring.vmId].invalidate(
|
2024-10-09 13:59:13 +02:00
|
|
|
scheduler, rx::AddressRange::fromBeginSize(dstAddress, size));
|
2024-09-30 21:43:21 +02:00
|
|
|
} else {
|
|
|
|
|
dst = getMmRegister(dstAddressLo / sizeof(std::uint32_t));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1:
|
2024-10-15 17:35:17 +02:00
|
|
|
dst = device->caches[ring.vmId].getGdsBuffer().getData() + dstAddressLo;
|
2024-09-30 21:43:21 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("IT_DMA_DATA: unexpected dstSel {}", dstSel);
|
2024-09-30 21:43:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *src = nullptr;
|
|
|
|
|
std::uint32_t srcSize = 0;
|
|
|
|
|
switch (srcSel) {
|
|
|
|
|
case 3:
|
|
|
|
|
case 0:
|
|
|
|
|
if (srcSel == 3 || sas == 0) {
|
|
|
|
|
auto srcAddress =
|
|
|
|
|
srcAddressLo | (static_cast<std::uint64_t>(srcAddressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
src = amdgpu::RemoteMemory{ring.vmId}.getPointer(srcAddress);
|
|
|
|
|
device->caches[ring.vmId].flush(
|
2024-10-09 13:59:13 +02:00
|
|
|
scheduler, rx::AddressRange::fromBeginSize(srcAddress, size));
|
2024-09-30 21:43:21 +02:00
|
|
|
} else {
|
|
|
|
|
src = getMmRegister(srcAddressLo / sizeof(std::uint32_t));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srcSize = ~0;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
2024-10-15 17:35:17 +02:00
|
|
|
src = device->caches[ring.vmId].getGdsBuffer().getData() + srcAddressLo;
|
2024-09-30 21:43:21 +02:00
|
|
|
srcSize = ~0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
src = &data;
|
|
|
|
|
srcSize = sizeof(data);
|
2024-10-05 00:08:21 +02:00
|
|
|
saic = 1;
|
2024-09-30 21:43:21 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("IT_DMA_DATA: unexpected srcSel {}", srcSel);
|
2024-09-30 21:43:21 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-05 00:08:21 +02:00
|
|
|
rx::dieIf(size > srcSize && saic == 0,
|
2025-10-04 13:23:42 +02:00
|
|
|
"IT_DMA_DATA: out of source size srcSel {}, dstSel {}, size {}",
|
2024-09-30 21:43:21 +02:00
|
|
|
srcSel, dstSel, size);
|
|
|
|
|
|
2024-10-05 00:08:21 +02:00
|
|
|
if (saic != 0) {
|
2024-09-30 22:15:55 +02:00
|
|
|
if (daic != 0 && dstSel == 0 && das == 1) {
|
2024-09-30 21:43:21 +02:00
|
|
|
std::memcpy(dst, src, sizeof(std::uint32_t));
|
|
|
|
|
} else {
|
|
|
|
|
for (std::uint32_t i = 0; i < size / sizeof(std::uint32_t); ++i) {
|
|
|
|
|
std::memcpy(std::bit_cast<std::uint32_t *>(dst) + i, src,
|
|
|
|
|
sizeof(std::uint32_t));
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-30 22:15:55 +02:00
|
|
|
} else if (daic != 0 && dstSel == 0 && das == 1) {
|
2024-09-30 21:43:21 +02:00
|
|
|
for (std::uint32_t i = 0; i < size / sizeof(std::uint32_t); ++i) {
|
|
|
|
|
std::memcpy(dst, std::bit_cast<std::uint32_t *>(src) + i,
|
|
|
|
|
sizeof(std::uint32_t));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
std::memcpy(dst, src, size);
|
|
|
|
|
}
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-20 21:22:37 +01:00
|
|
|
bool GraphicsPipe::loadUConfigReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16) - 1;
|
|
|
|
|
uint32_t addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
uint32_t addressHiOffset = ring.rptr[2];
|
|
|
|
|
auto ranges = (RegSpan *)(ring.rptr + 3);
|
|
|
|
|
|
|
|
|
|
constexpr auto mmioOffset = Registers::UConfig::kMmioOffset;
|
|
|
|
|
std::uint64_t address =
|
|
|
|
|
addressLo | (static_cast<std::uint64_t>(addressHiOffset) << 32);
|
|
|
|
|
auto data =
|
|
|
|
|
amdgpu::RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
|
|
|
|
|
|
|
|
|
for (auto range : std::span{ranges, len / 2}) {
|
|
|
|
|
// std::println(stderr, "loadUConfigReg: address={} regOffset={}
|
|
|
|
|
// numWords={}",
|
|
|
|
|
// data, range.offset, range.count);
|
|
|
|
|
// for (auto offset = range.offset;
|
|
|
|
|
// auto value : std::span{data, range.count}) {
|
|
|
|
|
// std::fprintf(stderr, "writing %x to %s\n", value,
|
|
|
|
|
// gnm::mmio::registerName(mmioOffset + offset));
|
|
|
|
|
// ++offset;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
std::memcpy(getMmRegister(mmioOffset + range.offset), data,
|
|
|
|
|
sizeof(std::uint32_t) * range.count);
|
|
|
|
|
data += range.count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GraphicsPipe::loadShReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16) - 1;
|
|
|
|
|
uint32_t addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
uint32_t addressHiOffset = ring.rptr[2];
|
|
|
|
|
auto ranges = (RegSpan *)(ring.rptr + 3);
|
|
|
|
|
|
|
|
|
|
constexpr auto mmioOffset = Registers::ShaderConfig::kMmioOffset;
|
|
|
|
|
std::uint64_t address =
|
|
|
|
|
addressLo | (static_cast<std::uint64_t>(addressHiOffset) << 32);
|
|
|
|
|
auto data =
|
|
|
|
|
amdgpu::RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
|
|
|
|
|
|
|
|
|
for (auto range : std::span{ranges, len / 2}) {
|
|
|
|
|
// std::println(stderr, "loadShReg: address={} regOffset={} numWords={}",
|
|
|
|
|
// data,
|
|
|
|
|
// range.offset, range.count);
|
|
|
|
|
// for (auto offset = range.offset;
|
|
|
|
|
// auto value : std::span{data, range.count}) {
|
|
|
|
|
// std::fprintf(stderr, "writing %x to %s\n", value,
|
|
|
|
|
// gnm::mmio::registerName(mmioOffset + offset));
|
|
|
|
|
// ++offset;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
std::memcpy(getMmRegister(mmioOffset + range.offset), data,
|
|
|
|
|
sizeof(std::uint32_t) * range.count);
|
|
|
|
|
data += range.count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GraphicsPipe::loadConfigReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16) - 1;
|
|
|
|
|
uint32_t addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
uint32_t addressHiOffset = ring.rptr[2];
|
|
|
|
|
auto ranges = (RegSpan *)(ring.rptr + 3);
|
|
|
|
|
|
|
|
|
|
constexpr auto mmioOffset = Registers::Config::kMmioOffset;
|
|
|
|
|
std::uint64_t address =
|
|
|
|
|
addressLo | (static_cast<std::uint64_t>(addressHiOffset) << 32);
|
|
|
|
|
auto data =
|
|
|
|
|
amdgpu::RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
|
|
|
|
|
|
|
|
|
for (auto range : std::span{ranges, len / 2}) {
|
|
|
|
|
// std::println(stderr, "loadConfigReg: address={} regOffset={}
|
|
|
|
|
// numWords={}",
|
|
|
|
|
// data, range.offset, range.count);
|
|
|
|
|
// for (auto offset = range.offset;
|
|
|
|
|
// auto value : std::span{data, range.count}) {
|
|
|
|
|
// std::fprintf(stderr, "writing %x to %s\n", value,
|
|
|
|
|
// gnm::mmio::registerName(mmioOffset + offset));
|
|
|
|
|
// ++offset;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
std::memcpy(getMmRegister(mmioOffset + range.offset), data,
|
|
|
|
|
sizeof(std::uint32_t) * range.count);
|
|
|
|
|
data += range.count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GraphicsPipe::loadContextReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16) - 1;
|
|
|
|
|
uint32_t addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
uint32_t addressHiOffset = ring.rptr[2];
|
|
|
|
|
auto ranges = (RegSpan *)(ring.rptr + 3);
|
|
|
|
|
|
|
|
|
|
constexpr auto mmioOffset = Registers::Context::kMmioOffset;
|
|
|
|
|
std::uint64_t address =
|
|
|
|
|
addressLo | (static_cast<std::uint64_t>(addressHiOffset) << 32);
|
|
|
|
|
auto data =
|
|
|
|
|
amdgpu::RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
|
|
|
|
|
|
|
|
|
for (auto range : std::span{ranges, len / 2}) {
|
|
|
|
|
// std::println(stderr, "loadContextReg: address={} regOffset={}
|
|
|
|
|
// numWords={}",
|
|
|
|
|
// data, range.offset, range.count);
|
|
|
|
|
// for (auto offset = range.offset;
|
|
|
|
|
// auto value : std::span{data, range.count}) {
|
|
|
|
|
// std::fprintf(stderr, "writing %x to %s\n", value,
|
|
|
|
|
// gnm::mmio::registerName(mmioOffset + offset));
|
|
|
|
|
// ++offset;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
std::memcpy(getMmRegister(mmioOffset + range.offset), data,
|
|
|
|
|
sizeof(std::uint32_t) * range.count);
|
|
|
|
|
data += range.count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::setConfigReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16);
|
|
|
|
|
auto offset = ring.rptr[1] & 0xffff;
|
|
|
|
|
auto data = ring.rptr + 2;
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-10-23 01:32:43 +02:00
|
|
|
auto mmioOffset = decltype(device->config)::kMmioOffset + offset;
|
|
|
|
|
|
|
|
|
|
// FIXME: verify
|
|
|
|
|
if (mmioOffset >= decltype(context)::kMmioOffset) {
|
|
|
|
|
auto contextOffset = mmioOffset - decltype(context)::kMmioOffset;
|
|
|
|
|
|
|
|
|
|
if (contextOffset + len <= sizeof(context)) {
|
|
|
|
|
std::memcpy(reinterpret_cast<std::uint32_t *>(&context) + contextOffset,
|
2024-11-13 21:53:08 +01:00
|
|
|
const_cast<std::uint32_t *>(data),
|
|
|
|
|
sizeof(std::uint32_t) * len);
|
2024-10-23 01:32:43 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-25 15:00:55 +02:00
|
|
|
rx::dieIf(
|
|
|
|
|
(offset + len) * sizeof(std::uint32_t) > sizeof(device->config),
|
2024-09-29 20:37:12 +02:00
|
|
|
"out of Config regs, offset: %x, count %u, %s\n", offset, len,
|
2024-09-25 15:00:55 +02:00
|
|
|
gnm::mmio::registerName(decltype(device->config)::kMmioOffset + offset));
|
|
|
|
|
|
2024-11-13 21:53:08 +01:00
|
|
|
std::memcpy(reinterpret_cast<std::uint32_t *>(&device->config) + offset,
|
|
|
|
|
const_cast<std::uint32_t *>(data), sizeof(std::uint32_t) * len);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::setShReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16);
|
|
|
|
|
auto offset = ring.rptr[1] & 0xffff;
|
|
|
|
|
auto index = ring.rptr[1] >> 26;
|
|
|
|
|
auto data = ring.rptr + 2;
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
rx::dieIf((offset + len) * sizeof(std::uint32_t) > sizeof(sh),
|
2025-10-04 13:23:42 +02:00
|
|
|
"out of SH regs, offset: {:x}, count {}, {}\n", offset, len,
|
2024-09-25 15:00:55 +02:00
|
|
|
gnm::mmio::registerName(decltype(sh)::kMmioOffset + offset));
|
|
|
|
|
|
2024-11-13 21:53:08 +01:00
|
|
|
std::memcpy(reinterpret_cast<std::uint32_t *>(&sh) + offset,
|
|
|
|
|
const_cast<std::uint32_t *>(data), sizeof(std::uint32_t) * len);
|
2024-10-06 03:06:44 +02:00
|
|
|
// for (std::size_t i = 0; i < len; ++i) {
|
|
|
|
|
// std::fprintf(
|
|
|
|
|
// stderr, "writing to %s value %x\n",
|
|
|
|
|
// gnm::mmio::registerName(decltype(sh)::kMmioOffset + offset + i),
|
|
|
|
|
// data[i]);
|
|
|
|
|
// }
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::setUConfigReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16);
|
|
|
|
|
auto offset = ring.rptr[1] & 0xffff;
|
|
|
|
|
auto index = ring.rptr[1] >> 26;
|
|
|
|
|
auto data = ring.rptr + 2;
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-11-20 21:22:37 +01:00
|
|
|
// if (index != 0) {
|
|
|
|
|
// {
|
|
|
|
|
// auto name =
|
|
|
|
|
// gnm::mmio::registerName(decltype(uConfig)::kMmioOffset + offset);
|
|
|
|
|
// std::println(
|
|
|
|
|
// stderr,
|
|
|
|
|
// "set UConfig regs with index, offset: {:x}, count {}, index {},
|
|
|
|
|
// {}", offset, len, index, name ? name : "<null>");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// for (std::size_t i = 0; i < len; ++i) {
|
|
|
|
|
// auto id = decltype(uConfig)::kMmioOffset + offset + i;
|
|
|
|
|
// if (auto regName = gnm::mmio::registerName(id)) {
|
|
|
|
|
// std::println(stderr, "writing to {} value {:x}", regName,
|
|
|
|
|
// uint32_t(data[i]));
|
|
|
|
|
// } else {
|
|
|
|
|
// std::println(stderr, "writing to {:x} value {:x}", id,
|
|
|
|
|
// uint32_t(data[i]));
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2024-09-29 20:37:12 +02:00
|
|
|
|
|
|
|
|
rx::dieIf((offset + len) * sizeof(std::uint32_t) > sizeof(context),
|
2025-10-04 13:23:42 +02:00
|
|
|
"out of UConfig regs, offset: {:x}, count {}, {}\n", offset, len,
|
2024-09-25 15:00:55 +02:00
|
|
|
gnm::mmio::registerName(decltype(uConfig)::kMmioOffset + offset));
|
|
|
|
|
|
2024-11-13 21:53:08 +01:00
|
|
|
std::memcpy(reinterpret_cast<std::uint32_t *>(&uConfig) + offset,
|
|
|
|
|
const_cast<std::uint32_t *>(data), sizeof(std::uint32_t) * len);
|
2024-10-06 03:06:44 +02:00
|
|
|
// for (std::size_t i = 0; i < len; ++i) {
|
|
|
|
|
// std::fprintf(
|
|
|
|
|
// stderr, "writing to %s value %x\n",
|
|
|
|
|
// gnm::mmio::registerName(decltype(uConfig)::kMmioOffset + offset + i),
|
|
|
|
|
// data[i]);
|
|
|
|
|
// }
|
2024-09-25 15:00:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::setContextReg(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16);
|
|
|
|
|
auto offset = ring.rptr[1] & 0xffff;
|
|
|
|
|
auto index = ring.rptr[1] >> 26;
|
|
|
|
|
auto data = ring.rptr + 2;
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2024-11-20 21:22:37 +01:00
|
|
|
// if (index != 0) {
|
|
|
|
|
// {
|
|
|
|
|
// auto name =
|
|
|
|
|
// gnm::mmio::registerName(decltype(context)::kMmioOffset + offset);
|
|
|
|
|
// std::println(
|
|
|
|
|
// stderr,
|
|
|
|
|
// "set Context regs with index, offset: {:x}, count {}, index {},
|
|
|
|
|
// {}", offset, len, index, name ? name : "<null>");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// for (std::size_t i = 0; i < len; ++i) {
|
|
|
|
|
// auto id = decltype(context)::kMmioOffset + offset + i;
|
|
|
|
|
// if (auto regName = gnm::mmio::registerName(id)) {
|
|
|
|
|
// std::println(stderr, "writing to {} value {:x}", regName,
|
|
|
|
|
// uint32_t(data[i]));
|
|
|
|
|
// } else {
|
|
|
|
|
// std::println(stderr, "writing to {:x} value {:x}", id,
|
|
|
|
|
// uint32_t(data[i]));
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2024-09-29 20:37:12 +02:00
|
|
|
|
2024-09-25 15:00:55 +02:00
|
|
|
rx::dieIf((offset + len) * sizeof(std::uint32_t) > sizeof(context),
|
2025-10-04 13:23:42 +02:00
|
|
|
"out of Context regs, offset: {:x}, count {}, {}\n", offset, len,
|
2024-09-25 15:00:55 +02:00
|
|
|
gnm::mmio::registerName(decltype(context)::kMmioOffset + offset));
|
|
|
|
|
|
2024-11-13 21:53:08 +01:00
|
|
|
std::memcpy(reinterpret_cast<std::uint32_t *>(&context) + offset,
|
|
|
|
|
const_cast<std::uint32_t *>(data), sizeof(std::uint32_t) * len);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
|
|
|
|
// for (std::size_t i = 0; i < len; ++i) {
|
2024-10-06 03:06:44 +02:00
|
|
|
// std::fprintf(
|
|
|
|
|
// stderr, "writing to %s value %x\n",
|
2024-09-25 15:00:55 +02:00
|
|
|
// gnm::mmio::registerName(decltype(context)::kMmioOffset + offset + i),
|
|
|
|
|
// data[i]);
|
|
|
|
|
// }
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::setCeDeCounters(Ring &ring) {
|
|
|
|
|
auto counterLo = ring.rptr[1];
|
|
|
|
|
auto counterHi = ring.rptr[2];
|
2024-09-25 15:00:55 +02:00
|
|
|
auto counter = counterLo | (static_cast<std::uint64_t>(counterHi) << 32);
|
|
|
|
|
deCounter = counter;
|
|
|
|
|
ceCounter = counter;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::waitOnCeCounter(Ring &ring) {
|
|
|
|
|
auto counterLo = ring.rptr[1];
|
|
|
|
|
auto counterHi = ring.rptr[2];
|
2024-09-25 15:00:55 +02:00
|
|
|
auto counter = counterLo | (static_cast<std::uint64_t>(counterHi) << 32);
|
|
|
|
|
return deCounter >= counter;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::waitOnDeCounterDiff(Ring &ring) {
|
|
|
|
|
auto waitDiff = ring.rptr[1];
|
2024-09-25 15:00:55 +02:00
|
|
|
auto diff = ceCounter - deCounter;
|
|
|
|
|
return diff < waitDiff;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::incrementCeCounter(Ring &) {
|
2024-09-25 15:00:55 +02:00
|
|
|
ceCounter++;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::incrementDeCounter(Ring &) {
|
2024-09-25 15:00:55 +02:00
|
|
|
deCounter++;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::loadConstRam(Ring &ring) {
|
|
|
|
|
std::uint32_t addressLo = ring.rptr[1];
|
|
|
|
|
std::uint32_t addressHi = ring.rptr[2];
|
|
|
|
|
std::uint32_t numDw = ring.rptr[3] & ((1 << 15) - 1);
|
2024-09-25 15:00:55 +02:00
|
|
|
std::uint32_t offset =
|
2024-10-15 17:35:17 +02:00
|
|
|
(ring.rptr[4] & ((1 << 16) - 1)) / sizeof(std::uint32_t);
|
2024-09-25 15:00:55 +02:00
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
std::memcpy(constantMemory + offset,
|
2024-10-15 17:35:17 +02:00
|
|
|
RemoteMemory{ring.vmId}.getPointer(address),
|
2024-09-25 15:00:55 +02:00
|
|
|
numDw * sizeof(std::uint32_t));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::writeConstRam(Ring &ring) {
|
2024-09-25 15:00:55 +02:00
|
|
|
std::uint32_t offset =
|
2024-10-15 17:35:17 +02:00
|
|
|
(ring.rptr[1] & ((1 << 16) - 1)) / sizeof(std::uint32_t);
|
|
|
|
|
std::uint32_t data = ring.rptr[2];
|
2024-09-25 15:00:55 +02:00
|
|
|
std::memcpy(constantMemory + offset, &data, sizeof(std::uint32_t));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::dumpConstRam(Ring &ring) {
|
2024-09-25 15:00:55 +02:00
|
|
|
std::uint32_t offset =
|
2024-10-15 17:35:17 +02:00
|
|
|
(ring.rptr[1] & ((1 << 16) - 1)) / sizeof(std::uint32_t);
|
|
|
|
|
std::uint32_t numDw = ring.rptr[2] & ((1 << 15) - 1);
|
|
|
|
|
std::uint32_t addressLo = ring.rptr[3];
|
|
|
|
|
std::uint32_t addressHi = ring.rptr[4];
|
2024-09-25 15:00:55 +02:00
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
2024-10-15 17:35:17 +02:00
|
|
|
std::memcpy(RemoteMemory{ring.vmId}.getPointer(address),
|
2024-09-25 15:00:55 +02:00
|
|
|
constantMemory + offset, numDw * sizeof(std::uint32_t));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::unknownPacket(Ring &ring) {
|
|
|
|
|
auto op = rx::getBits(ring.rptr[0], 15, 8);
|
2024-09-25 15:00:55 +02:00
|
|
|
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unimplemented gfx pm4 packet: {}, queue {}",
|
2024-10-15 17:35:17 +02:00
|
|
|
gnm::pm4OpcodeToString(op), ring.indirectLevel);
|
2024-09-25 15:00:55 +02:00
|
|
|
}
|
2024-10-12 04:24:58 +02:00
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::switchBuffer(Ring &ring) {
|
2024-10-12 04:24:58 +02:00
|
|
|
// FIXME: implement
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::mapQueues(Ring &ring) {
|
2024-10-12 04:24:58 +02:00
|
|
|
// FIXME: implement
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 17:35:17 +02:00
|
|
|
bool GraphicsPipe::unmapQueues(Ring &ring) {
|
2024-10-12 04:24:58 +02:00
|
|
|
// FIXME: implement
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-20 21:22:37 +01:00
|
|
|
bool GraphicsPipe::waitRegMem64(Ring &ring) {
|
|
|
|
|
// FIXME: implement
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GraphicsPipe::loadContextRegIndex(Ring &ring) {
|
|
|
|
|
uint32_t index = ring.rptr[1] & 1;
|
|
|
|
|
uint32_t addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
uint32_t addressHiOffset = ring.rptr[2];
|
|
|
|
|
uint32_t regOffset = ring.rptr[3] & ((1 << 16) - 1);
|
|
|
|
|
uint32_t dataFormat = ring.rptr[3] >> 31;
|
|
|
|
|
uint32_t numWords = (ring.rptr[4] & ((1 << 14) - 1));
|
|
|
|
|
|
|
|
|
|
if (index == 0) {
|
|
|
|
|
// direct address
|
|
|
|
|
} else {
|
|
|
|
|
// offset
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("{}: unimplemented index 1", __FUNCTION__);
|
2024-11-20 21:22:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// std::println(
|
|
|
|
|
// stderr,
|
|
|
|
|
// "loadContextRegIndex: index={} addressLo={:x} addressHiOffset={:x} "
|
|
|
|
|
// "regOffset={} dataFormat={} numWords={}",
|
|
|
|
|
// index, addressLo, addressHiOffset, regOffset, dataFormat, numWords);
|
|
|
|
|
std::uint64_t address =
|
|
|
|
|
addressLo | (static_cast<std::uint64_t>(addressHiOffset) << 32);
|
|
|
|
|
auto data =
|
|
|
|
|
amdgpu::RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
|
|
|
|
|
|
|
|
|
constexpr auto mmioOffset = Registers::Context::kMmioOffset;
|
|
|
|
|
|
|
|
|
|
if (dataFormat == 0) {
|
|
|
|
|
// offset and size
|
|
|
|
|
// for (auto offset = regOffset; auto value : std::span{data, numWords}) {
|
|
|
|
|
// if (auto name = gnm::mmio::registerName(mmioOffset + offset)) {
|
|
|
|
|
// std::println(stderr, "writing {:x} to {}", value, name);
|
|
|
|
|
// } else {
|
|
|
|
|
// std::println(stderr, "writing {:x} to {:x}", value,
|
|
|
|
|
// mmioOffset + offset);
|
|
|
|
|
// }
|
|
|
|
|
// ++offset;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
std::memcpy(getMmRegister(mmioOffset + regOffset), data,
|
|
|
|
|
sizeof(std::uint32_t) * numWords);
|
|
|
|
|
} else {
|
|
|
|
|
// offset and data
|
|
|
|
|
|
|
|
|
|
for (auto value :
|
|
|
|
|
std::span{(std::pair<std::uint32_t, std::uint32_t> *)data, numWords}) {
|
|
|
|
|
// if (auto name = gnm::mmio::registerName(mmioOffset + value.first)) {
|
|
|
|
|
// std::println(stderr, "writing {:x} to {}", value.second, name);
|
|
|
|
|
// } else {
|
|
|
|
|
// std::println(stderr, "writing {:x} to {:x}", value.second,
|
|
|
|
|
// mmioOffset + value.first);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
auto regPtr = getMmRegister(mmioOffset + value.first);
|
|
|
|
|
|
|
|
|
|
*regPtr = value.second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GraphicsPipe::loadShRegIndex(Ring &ring) {
|
|
|
|
|
uint32_t index = ring.rptr[1] & 1;
|
|
|
|
|
uint32_t addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
uint32_t addressHiOffset = ring.rptr[2];
|
|
|
|
|
uint32_t regOffset = ring.rptr[3] & ((1 << 16) - 1);
|
|
|
|
|
uint32_t dataFormat = ring.rptr[3] >> 31;
|
|
|
|
|
uint32_t numWords = (ring.rptr[4] & ((1 << 14) - 1));
|
|
|
|
|
|
|
|
|
|
if (index == 0) {
|
|
|
|
|
// direct address
|
|
|
|
|
} else {
|
|
|
|
|
// offset
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("{}: unimplemented index 1", __FUNCTION__);
|
2024-11-20 21:22:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataFormat == 0) {
|
|
|
|
|
// offset and size
|
|
|
|
|
} else {
|
|
|
|
|
// offset and data
|
|
|
|
|
}
|
|
|
|
|
// std::println(stderr,
|
|
|
|
|
// "loadShRegIndex: index={} addressLo={:x} addressHiOffset={:x}
|
|
|
|
|
// " "regOffset={} dataFormat={} numWords={}", index, addressLo,
|
|
|
|
|
// addressHiOffset, regOffset, dataFormat, numWords);
|
|
|
|
|
std::uint64_t address =
|
|
|
|
|
addressLo | (static_cast<std::uint64_t>(addressHiOffset) << 32);
|
|
|
|
|
auto data =
|
|
|
|
|
amdgpu::RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
|
|
|
|
|
|
|
|
|
constexpr auto mmioOffset = Registers::ShaderConfig::kMmioOffset;
|
|
|
|
|
|
|
|
|
|
if (dataFormat == 0) {
|
|
|
|
|
// offset and size
|
|
|
|
|
// for (auto offset = regOffset; auto value : std::span{data, numWords}) {
|
|
|
|
|
// std::fprintf(stderr, "writing %x to %s\n", value,
|
|
|
|
|
// gnm::mmio::registerName(mmioOffset + offset));
|
|
|
|
|
// ++offset;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
std::memcpy(getMmRegister(mmioOffset + regOffset), data,
|
|
|
|
|
sizeof(std::uint32_t) * numWords);
|
|
|
|
|
} else {
|
|
|
|
|
// offset and data
|
|
|
|
|
|
|
|
|
|
for (auto value :
|
|
|
|
|
std::span{(std::pair<std::uint32_t, std::uint32_t> *)data, numWords}) {
|
|
|
|
|
// std::fprintf(stderr, "writing %x to %s\n", value.second,
|
|
|
|
|
// gnm::mmio::registerName(mmioOffset + value.first));
|
|
|
|
|
|
|
|
|
|
auto regPtr = getMmRegister(mmioOffset + value.first);
|
|
|
|
|
|
|
|
|
|
*regPtr = value.second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GraphicsPipe::loadUConfigRegIndex(Ring &ring) {
|
|
|
|
|
uint32_t index = ring.rptr[1] & 1;
|
|
|
|
|
uint32_t addressLo = ring.rptr[1] & ~3;
|
|
|
|
|
uint32_t addressHiOffset = ring.rptr[2];
|
|
|
|
|
uint32_t regOffset = ring.rptr[3] & ((1 << 16) - 1);
|
|
|
|
|
uint32_t dataFormat = ring.rptr[3] >> 31;
|
|
|
|
|
uint32_t numWords = (ring.rptr[4] & ((1 << 14) - 1));
|
|
|
|
|
|
|
|
|
|
if (index == 0) {
|
|
|
|
|
// direct address
|
|
|
|
|
} else {
|
|
|
|
|
// offset
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("{}: unimplemented index 1", __FUNCTION__);
|
2024-11-20 21:22:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataFormat == 0) {
|
|
|
|
|
// offset and size
|
|
|
|
|
} else {
|
|
|
|
|
// offset and data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// std::println(
|
|
|
|
|
// stderr,
|
|
|
|
|
// "loadUConfigRegIndex: index={} addressLo={:x} addressHiOffset={:x} "
|
|
|
|
|
// "regOffset={} dataFormat={} numWords={}",
|
|
|
|
|
// index, addressLo, addressHiOffset, regOffset, dataFormat, numWords);
|
|
|
|
|
// FIXME: implement
|
|
|
|
|
std::uint64_t address =
|
|
|
|
|
addressLo | (static_cast<std::uint64_t>(addressHiOffset) << 32);
|
|
|
|
|
auto data =
|
|
|
|
|
amdgpu::RemoteMemory{ring.vmId}.getPointer<std::uint32_t>(address);
|
|
|
|
|
|
|
|
|
|
constexpr auto mmioOffset = Registers::UConfig::kMmioOffset;
|
|
|
|
|
|
|
|
|
|
if (dataFormat == 0) {
|
|
|
|
|
// offset and size
|
|
|
|
|
// for (auto offset = regOffset; auto value : std::span{data, numWords}) {
|
|
|
|
|
// std::fprintf(stderr, "writing %x to %s\n", value,
|
|
|
|
|
// gnm::mmio::registerName(mmioOffset + offset));
|
|
|
|
|
// ++offset;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
std::memcpy(getMmRegister(mmioOffset + regOffset), data,
|
|
|
|
|
sizeof(std::uint32_t) * numWords);
|
|
|
|
|
} else {
|
|
|
|
|
// offset and data
|
|
|
|
|
|
|
|
|
|
for (auto value :
|
|
|
|
|
std::span{(std::pair<std::uint32_t, std::uint32_t> *)data, numWords}) {
|
|
|
|
|
// std::fprintf(stderr, "writing %x to %s\n", value.second,
|
|
|
|
|
// gnm::mmio::registerName(mmioOffset + value.first));
|
|
|
|
|
|
|
|
|
|
auto regPtr = getMmRegister(mmioOffset + value.first);
|
|
|
|
|
|
|
|
|
|
*regPtr = value.second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GraphicsPipe::setUConfigRegIndex(Ring &ring) {
|
|
|
|
|
auto len = rx::getBits(ring.rptr[0], 29, 16);
|
|
|
|
|
auto offset = ring.rptr[1] & 0xffff;
|
|
|
|
|
auto data = ring.rptr + 2;
|
|
|
|
|
|
|
|
|
|
rx::dieIf((offset + len) * sizeof(std::uint32_t) > sizeof(context),
|
2025-10-04 13:23:42 +02:00
|
|
|
"out of UConfig regs, offset: {:x}, count {}, {}\n", offset, len,
|
2024-11-20 21:22:37 +01:00
|
|
|
gnm::mmio::registerName(decltype(uConfig)::kMmioOffset + offset));
|
|
|
|
|
|
|
|
|
|
// for (std::size_t i = 0; i < len; ++i) {
|
|
|
|
|
// auto id = decltype(uConfig)::kMmioOffset + offset + i;
|
|
|
|
|
// if (auto regName = gnm::mmio::registerName(id)) {
|
|
|
|
|
// std::println(stderr, "writing to {} value {:x}", regName,
|
|
|
|
|
// uint32_t(data[i]));
|
|
|
|
|
// } else {
|
2025-04-05 21:50:45 +02:00
|
|
|
// std::println(stderr, "writing to {:x} value {:x}", id,
|
|
|
|
|
// uint32_t(data[i]));
|
2024-11-20 21:22:37 +01:00
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
std::memcpy(reinterpret_cast<std::uint32_t *>(&uConfig) + offset,
|
|
|
|
|
const_cast<std::uint32_t *>(data), sizeof(std::uint32_t) * len);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-19 14:44:32 +02:00
|
|
|
CommandPipe::CommandPipe() {
|
|
|
|
|
for (auto &handler : commandHandlers) {
|
|
|
|
|
handler = &CommandPipe::unknownPacket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
commandHandlers[gnm::IT_MAP_PROCESS] = &CommandPipe::mapProcess;
|
|
|
|
|
commandHandlers[IT_MAP_MEMORY] = &CommandPipe::mapMemory;
|
|
|
|
|
commandHandlers[IT_UNMAP_MEMORY] = &CommandPipe::unmapMemory;
|
|
|
|
|
commandHandlers[IT_PROTECT_MEMORY] = &CommandPipe::protectMemory;
|
|
|
|
|
commandHandlers[IT_UNMAP_PROCESS] = &CommandPipe::unmapProcess;
|
|
|
|
|
commandHandlers[IT_FLIP] = &CommandPipe::flip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CommandPipe::processAllRings() { processRing(ring); }
|
|
|
|
|
|
|
|
|
|
void CommandPipe::processRing(Ring &ring) {
|
|
|
|
|
while (ring.rptr != ring.wptr) {
|
|
|
|
|
if (ring.rptr >= ring.base + ring.size) {
|
|
|
|
|
ring.rptr = ring.base;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto header = *ring.rptr;
|
|
|
|
|
auto type = rx::getBits(header, 31, 30);
|
|
|
|
|
|
|
|
|
|
if (type == 3) {
|
|
|
|
|
auto op = rx::getBits(header, 15, 8);
|
|
|
|
|
auto len = rx::getBits(header, 29, 16) + 2;
|
|
|
|
|
|
|
|
|
|
if (op == gnm::IT_COND_EXEC) {
|
|
|
|
|
rx::die("unimplemented COND_EXEC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto handler = commandHandlers[op];
|
|
|
|
|
(this->*handler)(ring);
|
|
|
|
|
|
|
|
|
|
ring.rptr += len;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type == 2) {
|
|
|
|
|
++ring.rptr;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("cmd pipe: unexpected pm4 packet type {}, ring {}, header {}, rptr "
|
|
|
|
|
"{}, wptr "
|
|
|
|
|
"{}, base {}, end {}",
|
|
|
|
|
type, ring.indirectLevel, header, (void *)ring.rptr,
|
|
|
|
|
(void *)ring.wptr, (void *)ring.base,
|
|
|
|
|
(void *)(ring.base + ring.size));
|
2024-10-19 14:44:32 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CommandPipe::mapMemory(Ring &ring) {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto pid = ring.rptr[1];
|
|
|
|
|
auto addressLo = ring.rptr[2];
|
|
|
|
|
auto addressHi = ring.rptr[3];
|
|
|
|
|
auto sizeLo = ring.rptr[4];
|
|
|
|
|
auto sizeHi = ring.rptr[5];
|
2025-11-30 13:46:37 +01:00
|
|
|
auto memoryType = orbis::MemoryType(ring.rptr[6]);
|
|
|
|
|
// auto dmemIndex = ring.rptr[7];
|
|
|
|
|
auto prot =
|
|
|
|
|
rx::EnumBitSet<orbis::vmem::Protection>::fromUnderlying(ring.rptr[8]);
|
2024-10-15 17:35:17 +02:00
|
|
|
auto offsetLo = ring.rptr[9];
|
|
|
|
|
auto offsetHi = ring.rptr[10];
|
2024-10-12 04:24:58 +02:00
|
|
|
|
|
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
auto size = sizeLo | (static_cast<std::uint64_t>(sizeHi) << 32);
|
|
|
|
|
auto offset = offsetLo | (static_cast<std::uint64_t>(offsetHi) << 32);
|
|
|
|
|
|
2025-11-30 13:46:37 +01:00
|
|
|
device->mapMemory(pid, rx::AddressRange::fromBeginSize(address, size),
|
|
|
|
|
memoryType, prot, offset);
|
2024-10-12 04:24:58 +02:00
|
|
|
}
|
2024-10-19 14:44:32 +02:00
|
|
|
void CommandPipe::unmapMemory(Ring &ring) {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto pid = ring.rptr[1];
|
|
|
|
|
auto addressLo = ring.rptr[2];
|
|
|
|
|
auto addressHi = ring.rptr[3];
|
|
|
|
|
auto sizeLo = ring.rptr[4];
|
|
|
|
|
auto sizeHi = ring.rptr[5];
|
2024-10-12 04:24:58 +02:00
|
|
|
|
|
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
auto size = sizeLo | (static_cast<std::uint64_t>(sizeHi) << 32);
|
|
|
|
|
device->unmapMemory(pid, address, size);
|
|
|
|
|
}
|
2024-10-19 14:44:32 +02:00
|
|
|
void CommandPipe::protectMemory(Ring &ring) {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto pid = ring.rptr[1];
|
|
|
|
|
auto addressLo = ring.rptr[2];
|
|
|
|
|
auto addressHi = ring.rptr[3];
|
|
|
|
|
auto sizeLo = ring.rptr[4];
|
|
|
|
|
auto sizeHi = ring.rptr[5];
|
2025-11-30 13:46:37 +01:00
|
|
|
auto prot =
|
|
|
|
|
rx::EnumBitSet<orbis::vmem::Protection>::fromUnderlying(ring.rptr[6]);
|
2024-10-12 04:24:58 +02:00
|
|
|
auto address = addressLo | (static_cast<std::uint64_t>(addressHi) << 32);
|
|
|
|
|
auto size = sizeLo | (static_cast<std::uint64_t>(sizeHi) << 32);
|
|
|
|
|
|
|
|
|
|
device->protectMemory(pid, address, size, prot);
|
|
|
|
|
}
|
2024-10-19 14:44:32 +02:00
|
|
|
void CommandPipe::mapProcess(Ring &ring) {
|
|
|
|
|
auto pid = ring.rptr[1];
|
|
|
|
|
int vmId = ring.rptr[2];
|
|
|
|
|
|
|
|
|
|
device->mapProcess(pid, vmId);
|
|
|
|
|
}
|
|
|
|
|
void CommandPipe::unmapProcess(Ring &ring) {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto pid = ring.rptr[1];
|
2024-10-12 04:24:58 +02:00
|
|
|
device->unmapProcess(pid);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-19 14:44:32 +02:00
|
|
|
void CommandPipe::flip(Ring &ring) {
|
2024-10-15 17:35:17 +02:00
|
|
|
auto buffer = ring.rptr[1];
|
|
|
|
|
auto dataLo = ring.rptr[2];
|
|
|
|
|
auto dataHi = ring.rptr[3];
|
|
|
|
|
auto pid = ring.rptr[4];
|
2024-10-12 04:24:58 +02:00
|
|
|
auto data = dataLo | (static_cast<std::uint64_t>(dataHi) << 32);
|
|
|
|
|
|
|
|
|
|
device->flip(pid, buffer, data);
|
2024-10-19 14:44:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CommandPipe::unknownPacket(Ring &ring) {
|
|
|
|
|
auto op = rx::getBits(ring.rptr[0], 15, 8);
|
|
|
|
|
|
2025-10-04 13:23:42 +02:00
|
|
|
rx::die("unexpected command pm4 packet: {}, queue {}\n",
|
2024-10-19 14:44:32 +02:00
|
|
|
gnm::pm4OpcodeToString(op), ring.indirectLevel);
|
2024-10-12 04:24:58 +02:00
|
|
|
}
|