Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ set(agcDriverSources
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawCapture.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawDecode.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawLookup.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawPipeline.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawPrecheck.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawRegisterKey.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawTiming.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_DRAW_DRAWPIPELINE_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_DRAW_DRAWPIPELINE_HPP

#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <exception>
#include <functional>
#include <mutex>
#include <optional>
#include <thread>
#include <utility>
#include <vector>

namespace AgcDriver::DriverDetail {

class DrawPipeline {
public:
using Commit = std::function<void()>;
using Range = std::pair<std::uint64_t, std::uint64_t>;
enum class DrainReason : std::uint8_t { Packet, Flush, Labels, Capture, Indirect, Submission, Count };

static DrawPipeline& Queue0();
static std::size_t Depth();
static bool& Active();
static std::atomic<std::uint64_t>& EpochToken();
static void FollowEpoch(std::uint64_t token);

void Enqueue(Commit commit, std::vector<Range> writes, std::uint64_t labelAddress = 0, std::vector<std::byte> labelBytes = {});
void Drain(DrainReason reason, std::uint32_t opcode = 0x100);
bool Busy() const { return outstanding.load(std::memory_order_acquire) != 0; }
bool Overlaps(std::uint64_t address, std::size_t bytes);
std::optional<std::uint64_t> PendingLabel(std::uint64_t address, std::size_t bytes);

private:
struct Item {
Commit commit;
std::vector<Range> writes;
std::uint64_t labelAddress = 0;
std::vector<std::byte> labelBytes;
};
DrawPipeline() = default;
void run();
void rethrowFailure();
void report(std::chrono::steady_clock::time_point now);

std::mutex mutex;
std::condition_variable wake;
std::condition_variable idle;
std::deque<Item> items;
std::exception_ptr failure;
std::atomic<std::size_t> outstanding{0};
std::uint32_t idleWaiters = 0;
bool committerWaiting = false;
std::thread thread;
std::uint64_t commits = 0;
std::uint64_t commitNs = 0;
std::uint64_t commitErrors = 0;
std::uint64_t enqueued = 0;
std::uint64_t fullWaitNs = 0;
std::array<std::uint64_t, static_cast<std::size_t>(DrainReason::Count)> drains{};
std::array<std::uint64_t, static_cast<std::size_t>(DrainReason::Count)> drainWaitNs{};
std::array<std::uint64_t, 257> drainOpcodes{};
std::uint64_t depthSum = 0;
std::chrono::steady_clock::time_point lastReport = std::chrono::steady_clock::now();
};

}

#endif
16 changes: 16 additions & 0 deletions core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ class Driver {
void enqueue(Submission submission);
void noteHeldAtSubmit(Submission& submission, std::size_t cursor);
static void forgetUnfinishedWrites(QueueWorker& worker, const Submission& submission);
static void forgetUnfinishedWrites(QueueWorker& worker, std::span<const std::uint64_t> labelWrites);
static bool& completionDeferred();
void deferCompletion(const Submission& submission);
void submitOpenWork();
void completeSubmission(std::uint64_t serial, std::uint64_t received, std::span<const std::uint64_t> labelWrites);
static bool waitFree(const Submission& submission);
bool queue0Before(std::uint64_t received) const;
bool orderReleased(std::uint32_t queue, std::uint64_t received) const;
Expand Down Expand Up @@ -207,6 +212,13 @@ class Driver {
static void appendWrittenRanges(const ShaderRecompiler::RecompileResult& compiled, std::vector<std::pair<std::uint64_t, std::uint64_t>>& ranges);
void noteForeignWriter(std::uint64_t begin, std::uint64_t end, std::uint32_t queue);
void noteDrawWriters(std::span<const Graphics::CompiledShader> stages, std::uint32_t queue);
static std::vector<std::pair<std::uint64_t, std::uint64_t>> drawWriteRanges(const Graphics::State& graphics, std::span<const Graphics::CompiledShader> stages);
void commitDraw(std::shared_ptr<VulkanDevice> localDevice, std::uint32_t queue, const Graphics::State& graphics, const Pm4::DrawParameters& drawParameters, std::span<const Graphics::CompiledShader> stages, std::span<const Graphics::GuestMemorySnapshot> snapshots, const std::shared_ptr<const DrawRecipe>& recipe, const std::vector<std::shared_ptr<DispatchVariant>>& recipeStages, std::uint64_t drawKey);
bool enqueueLabelPacket(std::span<const std::uint32_t> packet, std::uint32_t opcode, std::uint32_t queue);
bool enqueueDmaPacket(std::span<const std::uint32_t> packet, std::uint32_t opcode, std::uint32_t queue, const QueueState& state);
void commitDmaStore(std::uint32_t queue, std::uint64_t address, std::span<const std::byte> bytes);
void commitLabel(std::uint32_t queue, std::uint64_t address, std::span<const std::byte> bytes, bool endOfPipeInterrupt);
void submitDueAfterCommit(VulkanDevice* localDevice);
std::optional<WrittenBuffer> newestWriterLocked(std::uint64_t begin, std::uint64_t end) const;
std::optional<WrittenBuffer> newestWriter(std::uint64_t begin, std::uint64_t end);
std::string describeWriters(std::uint64_t begin, std::uint64_t end);
Expand Down Expand Up @@ -264,6 +276,9 @@ class Driver {
static Graphics::Recorder::LateStatistics& lateCountsSeen();
static EpochBumps& epochBumps();
static void bumpEpoch(std::uint64_t EpochBumps::*counter);
static std::chrono::steady_clock::time_point& lastEpochBump();
static std::deque<const std::uint32_t*>& releasedTails();
void noteReleasedTails(const Submission& submission);
static bool packetEpoch();
static bool labelTryEachPacket();
static std::chrono::microseconds labelFlushDeadline();
Expand Down Expand Up @@ -372,6 +387,7 @@ class Driver {

std::uint32_t idleWaiters = 0;
std::uint64_t queue0Executing = 0;
std::deque<std::uint64_t> queue0Uncommitted;
std::atomic<std::uint32_t> orderHolders{0};
std::atomic<std::uint32_t> runningWorkers{0};
std::atomic<std::uint64_t> idleEpoch{0};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_DRAWWRITERANGES_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_DRAWWRITERANGES_HPP

#include "prx/libSceAgcDriver/Graphics/include/Shaders.hpp"
#include "prx/libSceAgcDriver/Graphics/include/State.hpp"
#include <cstdint>
#include <span>
#include <utility>
#include <vector>

namespace AgcDriver::DriverDetail {

std::vector<std::pair<std::uint64_t, std::uint64_t>> DrawWriteRanges(const Graphics::State& graphics, std::span<const Graphics::CompiledShader> stages, bool exact);
bool ExactDrawWrites();

}

#endif
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "prx/libSceAgcDriver/Execution/include/ProfileOutput.hpp"
#include "prx/libSceAgcDriver/Execution/include/PerformanceTimer.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawPipeline.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Memory/BufferCopy.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Shaders/ShaderRegistry.hpp"
Expand Down Expand Up @@ -87,6 +88,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
pendingDispatchPhases().outcome = DispatchOutcome::FillHle;
return;
}
if (DrawPipeline::Active()) DrawPipeline::Queue0().Drain(DrawPipeline::DrainReason::Packet, 0x15);
if (!partialLastGroup && indirectArguments == 0 && copyBuffer(queue, submission.queue, packet, std::span(snapshot.code).subspan(codeOffset), userData, compute, localDevice, address)) {
pendingDispatchPhases().outcome = DispatchOutcome::CopyHle;
return;
Expand Down
44 changes: 44 additions & 0 deletions core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawPipeline.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Synchronization/DeferredLabels.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include "prx/libSceAgcDriver/Execution/include/PerformanceTimer.hpp"
#include "prx/libSceAgcDriver/Execution/include/Pm4.hpp"
Expand Down Expand Up @@ -30,6 +32,8 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
return DrawVerdict::Drawn;
};
auto drawParameters = Pm4::ResolveDraw(packet, queue);
const bool pipelined = DrawPipeline::Active();
if (pipelined && drawParameters.indirect) DrawPipeline::Queue0().Drain(DrawPipeline::DrainReason::Indirect);
bool traceIndirect = false;
if (const auto verdict = precheckDraw(queue, submission, packet, drawParameters, rejected, traceIndirect)) return *verdict;
phaseTiming.Phase(DrawRowPrecheck);
Expand Down Expand Up @@ -355,6 +359,7 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
for (const auto& read : reads) memory.push_back({read.address, std::as_bytes(std::span(read.bytes))});
}

if (pipelined && !deferredLabels().labels.empty()) DrawPipeline::Queue0().Drain(DrawPipeline::DrainReason::Labels);
if (recordQueuedLabelsAfterCapture(submission.queue, memory)) return draw(queue, packet, submission, rejected);

bool rectListBuilt = false;
Expand Down Expand Up @@ -503,6 +508,23 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
return DrawVerdict::Rejected;
}
}
if (pipelined && !drawParameters.indirect && deferredLabels().labels.empty()) {
phaseTiming.Phase(DrawRowVectors);
auto writes = drawWriteRanges(graphics, stages);
const auto commitQueue = submission.queue;
const auto commitPacket = (packet[0] >> 8u) & 0xffu;
const auto epoch = DrawPipeline::EpochToken().load(std::memory_order_relaxed);
auto commit = [this, localDevice = std::move(localDevice), decode = std::move(decode), drawParameters, stages = std::move(stages), snapshots = std::move(snapshots), recipe = std::move(recipe), recipeStages = std::move(recipeStages), drawKey, commitQueue, commitPacket, epoch, programs = std::move(programs), results = std::move(results), memory = std::move(memory), linked = std::move(linked), stageCaptures = std::move(stageCaptures), matched = std::move(matched), matchedRegions = std::move(matchedRegions), fresh = std::move(fresh), decodeReads = std::move(decodeReads), shaderMemory = std::move(shaderMemory), entry = std::move(entry), dataEntry = std::move(dataEntry)] {
DrawPipeline::FollowEpoch(epoch);
GuestMemory::SetCurrentPacket(commitPacket, commitQueue);
commitDraw(localDevice, commitQueue, decode->state, drawParameters, stages, snapshots, recipe, recipeStages, drawKey);
};
auto held = std::make_shared<decltype(commit)>(std::move(commit));
DrawPipeline::Queue0().Enqueue([held] { (*held)(); }, std::move(writes));
phaseTiming.Phase(DrawRowLockWait);
timing.Mark("draw_enqueued");
return drawn();
}
lockForDraw();
noteDrawWriters(stages, submission.queue);
phaseTiming.Phase(DrawRowVectors);
Expand All @@ -523,4 +545,26 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
return drawn();
}

void Driver::commitDraw(std::shared_ptr<VulkanDevice> localDevice, std::uint32_t queue, const Graphics::State& graphics, const Pm4::DrawParameters& drawParameters, std::span<const Graphics::CompiledShader> stages, std::span<const Graphics::GuestMemorySnapshot> snapshots, const std::shared_ptr<const DrawRecipe>& recipe, const std::vector<std::shared_ptr<DispatchVariant>>& recipeStages, std::uint64_t drawKey) {
GuestMemory::TagGpuLockSite(GuestMemory::GpuLockSite::Draw);
std::lock_guard gpuLock(GuestMemory::GpuMutex());
if (auto current = device.Load(); current != nullptr && current != localDevice) localDevice = std::move(current);
struct SubmitDue {
Driver& driver;
const std::shared_ptr<VulkanDevice>& device;
~SubmitDue() noexcept(false) {
if (std::uncaught_exceptions() == 0) driver.submitDueAfterCommit(device.get());
}
} submitDue{*this, localDevice};
recordLabelsForPacket(localDevice.get(), queue);
noteDrawWriters(stages, queue);
if (recipe != nullptr) {
if (localDevice->DrawFromRecipe(graphics, drawParameters, stages, snapshots, recipe) == RecipeOutcome::Recorded) return;
VulkanDevice::NoteRecipe(VulkanDevice::RecipeEvent::Restart, VulkanDevice::RecipeKind::Draw);
}
std::shared_ptr<const DrawRecipe> built;
localDevice->Draw(graphics, drawParameters, stages, snapshots, recipeStages.empty() ? nullptr : &built);
if (built != nullptr) attachDrawRecipe(drawKey, recipeStages, std::move(built));
}

}
Loading
Loading