renderer_vulkan: Fix crashing when updating descriptors
* During pipeline configure the function would acquire some payload space from the descriptor update queue, write the descriptor data on the GPU thread and give the scheduler a pointer to the beginning of said space to update it later. TickFrame resets the payload cursor, used to track acquires, back to the beginning of the buffer. This wasn't a problem before since WaitWorker was called at the end of the frame but now it is. If a frame writes to a cursor before the scheduler catches up, it will crash * To fix this the payload buffer has been increased to account for the in flight frames that are allowed to exist now. TickFrame will switch between the payload spaces instead of resetting
This commit is contained in:
parent
2ad9acf795
commit
50791cb974
2 changed files with 17 additions and 4 deletions
|
@ -14,13 +14,18 @@ namespace Vulkan {
|
||||||
|
|
||||||
UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_)
|
UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_)
|
||||||
: device{device_}, scheduler{scheduler_} {
|
: device{device_}, scheduler{scheduler_} {
|
||||||
|
payload_start = payload.data();
|
||||||
payload_cursor = payload.data();
|
payload_cursor = payload.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDescriptorQueue::~UpdateDescriptorQueue() = default;
|
UpdateDescriptorQueue::~UpdateDescriptorQueue() = default;
|
||||||
|
|
||||||
void UpdateDescriptorQueue::TickFrame() {
|
void UpdateDescriptorQueue::TickFrame() {
|
||||||
payload_cursor = payload.data();
|
if (++frame_index >= FRAMES_IN_FLIGHT) {
|
||||||
|
frame_index = 0;
|
||||||
|
}
|
||||||
|
payload_start = payload.data() + frame_index * FRAME_PAYLOAD_SIZE;
|
||||||
|
payload_cursor = payload_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDescriptorQueue::Acquire() {
|
void UpdateDescriptorQueue::Acquire() {
|
||||||
|
@ -28,10 +33,10 @@ void UpdateDescriptorQueue::Acquire() {
|
||||||
// This is the maximum number of entries a single draw call might use.
|
// This is the maximum number of entries a single draw call might use.
|
||||||
static constexpr size_t MIN_ENTRIES = 0x400;
|
static constexpr size_t MIN_ENTRIES = 0x400;
|
||||||
|
|
||||||
if (std::distance(payload.data(), payload_cursor) + MIN_ENTRIES >= payload.max_size()) {
|
if (std::distance(payload_start, payload_cursor) + MIN_ENTRIES >= FRAME_PAYLOAD_SIZE) {
|
||||||
LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread");
|
LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread");
|
||||||
scheduler.WaitWorker();
|
scheduler.WaitWorker();
|
||||||
payload_cursor = payload.data();
|
payload_cursor = payload_start;
|
||||||
}
|
}
|
||||||
upload_start = payload_cursor;
|
upload_start = payload_cursor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,12 @@ struct DescriptorUpdateEntry {
|
||||||
};
|
};
|
||||||
|
|
||||||
class UpdateDescriptorQueue final {
|
class UpdateDescriptorQueue final {
|
||||||
|
// This should be plenty for the vast majority of cases. Most desktop platforms only
|
||||||
|
// provide up to 3 swapchain images.
|
||||||
|
static constexpr size_t FRAMES_IN_FLIGHT = 5;
|
||||||
|
static constexpr size_t FRAME_PAYLOAD_SIZE = 0x10000;
|
||||||
|
static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_);
|
explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_);
|
||||||
~UpdateDescriptorQueue();
|
~UpdateDescriptorQueue();
|
||||||
|
@ -73,9 +79,11 @@ private:
|
||||||
const Device& device;
|
const Device& device;
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
|
|
||||||
|
size_t frame_index{0};
|
||||||
DescriptorUpdateEntry* payload_cursor = nullptr;
|
DescriptorUpdateEntry* payload_cursor = nullptr;
|
||||||
|
DescriptorUpdateEntry* payload_start = nullptr;
|
||||||
const DescriptorUpdateEntry* upload_start = nullptr;
|
const DescriptorUpdateEntry* upload_start = nullptr;
|
||||||
std::array<DescriptorUpdateEntry, 0x10000> payload;
|
std::array<DescriptorUpdateEntry, PAYLOAD_SIZE> payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
Loading…
Reference in a new issue