This commit is contained in:
2026-08-15 21:48:23 +08:00
parent 26bbc29a16
commit 023250c0fc
45 changed files with 457 additions and 415 deletions
@@ -1,4 +1,5 @@
#include "Gpu_Completion_Service.h"
#include <algorithm>
#include <stdexcept>
#include <string>
#include <utility>
@@ -110,98 +111,119 @@ void Gpu_Completion_Service::wake() noexcept {
wake_condition_.notify_one();
}
void Gpu_Completion_Service::run() noexcept {
struct Device_Fences {
VkDevice device{VK_NULL_HANDLE};
std::vector<VkFence> fences;
};
std::vector<std::shared_ptr<Pending_Fence>> active;
active.reserve(static_cast<std::size_t>(default_capacity));
std::size_t wait_group_index{};
const auto finish = [this](const std::shared_ptr<Pending_Fence>& pending, VkResult result) {
Completion completion;
std::chrono::steady_clock::time_point watched_at{};
bool observe{};
{
std::lock_guard lock(pending->mutex);
completion = std::move(pending->completion);
watched_at = pending->watched_at;
observe = pending->observe;
pending->status = Pending_Fence::Status::canceled;
}
watched_.fetch_sub(1, std::memory_order_relaxed);
Result completion_result;
if (observe) {
const auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now() - watched_at).count();
completion_result.wait_duration_ns = duration > 0 ? static_cast<std::uint64_t>(duration) : 0;
}
if (result != VK_SUCCESS) {
try {
throw std::runtime_error("GPU fence wait failed with Vulkan result " + std::to_string(static_cast<int>(result)));
} catch (...) {
completion_result.error = std::current_exception();
}
}
try {
completion(std::move(completion_result));
} catch (...) {
}
release_slot();
};
for (;;) {
const std::uint64_t wake_generation = wake_generation_.load(std::memory_order_acquire);
std::shared_ptr<Pending_Fence> incoming;
while (pending_.try_pop(incoming))
active.push_back(std::move(incoming));
bool progressed{};
bool has_watched{};
std::vector<Device_Fences> groups;
for (auto iterator = active.begin(); iterator != active.end();) {
auto& pending = *iterator;
Pending_Fence::Status status;
VkDevice device{VK_NULL_HANDLE};
VkFence fence{VK_NULL_HANDLE};
Completion completion;
std::chrono::steady_clock::time_point watched_at{};
bool observe{};
Pending_Fence::Status status;
{
std::lock_guard lock(pending->mutex);
status = pending->status;
if (status == Pending_Fence::Status::watched) {
device = pending->device;
fence = pending->fence;
watched_at = pending->watched_at;
observe = pending->observe;
}
std::lock_guard lock((*iterator)->mutex);
status = (*iterator)->status;
device = (*iterator)->device;
fence = (*iterator)->fence;
}
if (status == Pending_Fence::Status::canceled) {
if (status == Pending_Fence::Status::canceled ||
(status == Pending_Fence::Status::reserved && stopping_.load(std::memory_order_acquire))) {
cancel_reserved(*iterator);
iterator = active.erase(iterator);
release_slot();
progressed = true;
continue;
}
if (status == Pending_Fence::Status::reserved) {
if (stopping_.load(std::memory_order_acquire)) {
cancel_reserved(pending);
iterator = active.erase(iterator);
release_slot();
progressed = true;
continue;
if (status == Pending_Fence::Status::watched) {
auto group = std::find_if(groups.begin(), groups.end(), [device](const Device_Fences& item) {
return item.device == device;
});
if (group == groups.end()) {
groups.push_back(Device_Fences{device, {}});
group = groups.end() - 1;
}
group->fences.push_back(fence);
}
++iterator;
}
if (stopping_.load(std::memory_order_acquire) && active.empty() && pending_.empty())
return;
if (groups.empty()) {
std::unique_lock lock(wait_mutex_);
if (wake_generation_.load(std::memory_order_acquire) == wake_generation) {
wake_condition_.wait(lock, [this, wake_generation] {
return wake_generation_.load(std::memory_order_acquire) != wake_generation;
});
}
continue;
}
wait_group_index %= groups.size();
const Device_Fences& group = groups[wait_group_index++];
const VkResult wait_result = vkWaitForFences(
group.device, static_cast<std::uint32_t>(group.fences.size()), group.fences.data(), VK_FALSE,
fence_wait_timeout_ns);
for (auto iterator = active.begin(); iterator != active.end();) {
VkDevice device{VK_NULL_HANDLE};
VkFence fence{VK_NULL_HANDLE};
Pending_Fence::Status status;
{
std::lock_guard lock((*iterator)->mutex);
status = (*iterator)->status;
device = (*iterator)->device;
fence = (*iterator)->fence;
}
if (status != Pending_Fence::Status::watched || device != group.device) {
++iterator;
continue;
}
has_watched = true;
const VkResult result = vkGetFenceStatus(device, fence);
VkResult result = wait_result;
if (wait_result == VK_SUCCESS || wait_result == VK_TIMEOUT)
result = vkGetFenceStatus(device, fence);
if (result == VK_NOT_READY) {
++iterator;
continue;
}
{
std::lock_guard lock(pending->mutex);
completion = std::move(pending->completion);
pending->status = Pending_Fence::Status::canceled;
}
watched_.fetch_sub(1, std::memory_order_relaxed);
Result completion_result;
if (observe) {
const auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now() - watched_at).count();
completion_result.wait_duration_ns = duration > 0 ? static_cast<std::uint64_t>(duration) : 0;
}
if (result != VK_SUCCESS) {
try {
throw std::runtime_error("GPU fence wait failed with Vulkan result " + std::to_string(static_cast<int>(result)));
} catch (...) {
completion_result.error = std::current_exception();
}
}
try {
completion(std::move(completion_result));
} catch (...) {
}
auto pending = *iterator;
iterator = active.erase(iterator);
release_slot();
progressed = true;
}
if (stopping_.load(std::memory_order_acquire) && active.empty() && pending_.empty())
return;
if (progressed)
continue;
std::unique_lock lock(wait_mutex_);
if (wake_generation_.load(std::memory_order_acquire) != wake_generation)
continue;
if (has_watched) {
wake_condition_.wait_for(lock, poll_interval, [this, wake_generation] {
return wake_generation_.load(std::memory_order_acquire) != wake_generation;
});
} else {
wake_condition_.wait(lock, [this, wake_generation] {
return wake_generation_.load(std::memory_order_acquire) != wake_generation;
});
finish(pending, result);
}
}
}
@@ -75,7 +75,7 @@ private:
void wake() noexcept;
void run() noexcept;
static constexpr std::ptrdiff_t default_capacity = 1024;
static constexpr auto poll_interval = std::chrono::microseconds(200);
static constexpr std::uint64_t fence_wait_timeout_ns = 1'000'000;
std::counting_semaphore<default_capacity> slots_{default_capacity};
oneapi::tbb::concurrent_bounded_queue<std::shared_ptr<Pending_Fence>> pending_;
std::mutex wait_mutex_;
+8
View File
@@ -0,0 +1,8 @@
"C:\Program Files\JetBrains\CLion 2026.1\bin\cmake\win\x64\bin\cmake.exe" -DCMAKE_BUILD_TYPE=Debug --preset vs2022_debug
-S D:\ae\proj\Renderive -B D:\ae\proj\Renderive\cmake-build-vs2022_debug
默认每次运行程序都通过CDB运行 D:\ae\ewdk\EWDK_22621_230929-1800\Program Files\Windows Kits\10\Debuggers\x64\cdb.exe
D:\ae\tools 可能会有有用的工具
运行前使用环境脚本 env.ps1