mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
fix cmpx fix cs init ordering implement s_mulk_i32, s_abs_i32, s_cmovk_i32, s_cmov_b32 and s_cmov_b64 fix s_mul_i32 fix s_cbranch_* for cs
200 lines
5.3 KiB
C++
200 lines
5.3 KiB
C++
#pragma once
|
|
|
|
#include "vk.hpp"
|
|
#include <chrono>
|
|
#include <condition_variable>
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <stop_token>
|
|
#include <thread>
|
|
#include <vector>
|
|
#include <vulkan/vulkan_core.h>
|
|
|
|
class Scheduler {
|
|
vk::Semaphore mSemaphore = vk::Semaphore::Create();
|
|
VkQueue mQueue;
|
|
unsigned mQueueFamily;
|
|
vk::CommandPool mCommandPool;
|
|
vk::CommandBuffer mCommandBuffer;
|
|
bool mIsEmpty = false;
|
|
|
|
std::uint64_t mNextSignal = 1;
|
|
std::mutex mTaskMutex;
|
|
std::condition_variable mTaskCv;
|
|
std::map<std::uint64_t, std::vector<std::move_only_function<void()>>> mTasks;
|
|
std::vector<std::move_only_function<void()>> mAfterSubmitTasks;
|
|
|
|
// std::jthread mThread = std::jthread{
|
|
// [this](std::stop_token stopToken) { schedulerEntry(stopToken); }};
|
|
|
|
public:
|
|
Scheduler(VkQueue queue, unsigned queueFamilyIndex)
|
|
: mQueue(queue), mQueueFamily(queueFamilyIndex) {
|
|
mCommandPool = vk::CommandPool::Create(queueFamilyIndex);
|
|
mCommandBuffer = mCommandPool.createOneTimeSubmitBuffer();
|
|
}
|
|
|
|
~Scheduler() {
|
|
// mThread.request_stop();
|
|
// mTaskCv.notify_one();
|
|
}
|
|
|
|
unsigned getQueueFamily() const { return mQueueFamily; }
|
|
VkQueue getQueue() const { return mQueue; }
|
|
VkCommandBuffer getCommandBuffer() {
|
|
mIsEmpty = false;
|
|
return mCommandBuffer;
|
|
}
|
|
|
|
Scheduler &submit() {
|
|
if (mIsEmpty) {
|
|
return *this;
|
|
}
|
|
mIsEmpty = true;
|
|
|
|
mCommandBuffer.end();
|
|
|
|
VkSemaphoreSubmitInfo waitSemSubmitInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
|
|
.semaphore = mSemaphore.getHandle(),
|
|
.value = mNextSignal - 1,
|
|
.stageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT,
|
|
};
|
|
|
|
VkSemaphoreSubmitInfo signalSemSubmitInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
|
|
.semaphore = mSemaphore.getHandle(),
|
|
.value = mNextSignal,
|
|
.stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,
|
|
};
|
|
|
|
VkCommandBufferSubmitInfo cmdBufferSubmitInfo{
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
|
|
.commandBuffer = mCommandBuffer,
|
|
};
|
|
|
|
VkSubmitInfo2 submitInfo{
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
|
|
.waitSemaphoreInfoCount = mNextSignal != 1 ? 1u : 0u,
|
|
.pWaitSemaphoreInfos = &waitSemSubmitInfo,
|
|
.commandBufferInfoCount = 1,
|
|
.pCommandBufferInfos = &cmdBufferSubmitInfo,
|
|
.signalSemaphoreInfoCount = 1,
|
|
.pSignalSemaphoreInfos = &signalSemSubmitInfo,
|
|
};
|
|
|
|
mCommandBuffer = mCommandPool.createOneTimeSubmitBuffer();
|
|
|
|
wait();
|
|
|
|
VK_VERIFY(vkQueueSubmit2(mQueue, 1, &submitInfo, VK_NULL_HANDLE));
|
|
|
|
++mNextSignal;
|
|
|
|
// then([afterSubmit = std::move(mAfterSubmitTasks)] mutable {
|
|
// for (auto &&fn : afterSubmit) {
|
|
// std::move(fn)();
|
|
// }
|
|
// });
|
|
|
|
// mAfterSubmitTasks.clear();
|
|
|
|
auto endIt = mTasks.upper_bound(mNextSignal - 1);
|
|
|
|
if (mAfterSubmitTasks.empty() && endIt == mTasks.end()) {
|
|
return *this;
|
|
}
|
|
|
|
auto afterSubmit = std::move(mAfterSubmitTasks);
|
|
mAfterSubmitTasks.clear();
|
|
|
|
wait();
|
|
|
|
while (!afterSubmit.empty()) {
|
|
auto task = std::move(afterSubmit.back());
|
|
afterSubmit.pop_back();
|
|
std::move(task)();
|
|
}
|
|
|
|
std::vector<std::move_only_function<void()>> taskList;
|
|
|
|
for (auto it = mTasks.begin(); it != mTasks.end(); it = mTasks.erase(it)) {
|
|
taskList.reserve(taskList.size() + it->second.size());
|
|
for (auto &&fn : it->second) {
|
|
taskList.push_back(std::move(fn));
|
|
}
|
|
}
|
|
|
|
for (auto &&task : taskList) {
|
|
std::move(task)();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
Scheduler &afterSubmit(std::move_only_function<void()> fn) {
|
|
mAfterSubmitTasks.push_back(std::move(fn));
|
|
return *this;
|
|
}
|
|
|
|
Scheduler &then(std::move_only_function<void()> fn) {
|
|
// auto signalValue = mNextSignal++;
|
|
// onComplete([this, signalValue, fn = std::move(fn)] mutable {
|
|
// mSemaphore.wait(signalValue - 1, UINT64_MAX);
|
|
// std::move(fn)();
|
|
// mSemaphore.signal(signalValue);
|
|
// });
|
|
wait();
|
|
fn();
|
|
return *this;
|
|
}
|
|
|
|
// Scheduler &onComplete(std::move_only_function<void()> fn) {
|
|
// std::unique_lock lock(mTaskMutex);
|
|
// mTasks[mNextSignal - 1].push_back(std::move(fn));
|
|
// mTaskCv.notify_one();
|
|
// return *this;
|
|
// }
|
|
|
|
std::uint64_t createExternalSubmit() { return mNextSignal++; }
|
|
void wait() const { mSemaphore.wait(mNextSignal - 1, UINT64_MAX); }
|
|
|
|
VkSemaphore getSemaphoreHandle() const { return mSemaphore.getHandle(); }
|
|
|
|
private:
|
|
void schedulerEntry(std::stop_token stopToken) {
|
|
std::vector<std::move_only_function<void()>> taskList;
|
|
while (!stopToken.stop_requested()) {
|
|
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
|
|
|
{
|
|
std::unique_lock lock(mTaskMutex);
|
|
while (mTasks.empty()) {
|
|
mTaskCv.wait(lock);
|
|
|
|
if (stopToken.stop_requested()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto value = mSemaphore.getCounterValue();
|
|
auto endIt = mTasks.upper_bound(value);
|
|
|
|
for (auto it = mTasks.begin(); it != mTasks.end();
|
|
it = mTasks.erase(it)) {
|
|
taskList.reserve(taskList.size() + it->second.size());
|
|
for (auto &&fn : it->second) {
|
|
taskList.push_back(std::move(fn));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto &&task : taskList) {
|
|
std::move(task)();
|
|
}
|
|
|
|
taskList.clear();
|
|
}
|
|
}
|
|
};
|