Attempt at synchronizing swap image writes between the main window and graphics backend.
Disabled for now due to device timeouts.
This commit is contained in:
parent
26d81abf52
commit
69be82c786
|
@ -47,6 +47,8 @@ struct SwapState {
|
|||
uintptr_t front_buffer_texture = 0;
|
||||
// Current back buffer, being updated by the CP.
|
||||
uintptr_t back_buffer_texture = 0;
|
||||
// Backend data
|
||||
void* backend_data = nullptr;
|
||||
// Whether the back buffer is dirty and a swap is pending.
|
||||
bool pending = false;
|
||||
};
|
||||
|
@ -115,7 +117,7 @@ class CommandProcessor {
|
|||
virtual bool SetupContext() = 0;
|
||||
virtual void ShutdownContext() = 0;
|
||||
|
||||
void WriteRegister(uint32_t index, uint32_t value);
|
||||
virtual void WriteRegister(uint32_t index, uint32_t value);
|
||||
|
||||
virtual void MakeCoherent();
|
||||
virtual void PrepareForWait();
|
||||
|
|
|
@ -49,14 +49,7 @@ void VulkanCommandProcessor::RequestFrameTrace(const std::wstring& root_path) {
|
|||
|
||||
void VulkanCommandProcessor::ClearCaches() {
|
||||
CommandProcessor::ClearCaches();
|
||||
|
||||
auto status = vkQueueWaitIdle(queue_);
|
||||
CheckResult(status, "vkQueueWaitIdle");
|
||||
|
||||
buffer_cache_->ClearCache();
|
||||
pipeline_cache_->ClearCache();
|
||||
render_cache_->ClearCache();
|
||||
texture_cache_->ClearCache();
|
||||
cache_clear_requested_ = true;
|
||||
}
|
||||
|
||||
bool VulkanCommandProcessor::SetupContext() {
|
||||
|
@ -89,15 +82,29 @@ bool VulkanCommandProcessor::SetupContext() {
|
|||
texture_cache_->texture_descriptor_set_layout());
|
||||
render_cache_ = std::make_unique<RenderCache>(register_file_, device_);
|
||||
|
||||
VkSemaphoreCreateInfo info;
|
||||
std::memset(&info, 0, sizeof(info));
|
||||
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
VkResult result = vkCreateSemaphore(
|
||||
*device_, &info, nullptr,
|
||||
reinterpret_cast<VkSemaphore*>(&swap_state_.backend_data));
|
||||
if (result != VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanCommandProcessor::ShutdownContext() {
|
||||
// TODO(benvanik): wait until idle.
|
||||
|
||||
vkDestroySemaphore(*device_,
|
||||
reinterpret_cast<VkSemaphore>(swap_state_.backend_data),
|
||||
nullptr);
|
||||
|
||||
if (swap_state_.front_buffer_texture) {
|
||||
// Free swap chain images.
|
||||
DestroySwapImages();
|
||||
// Free swap chain image.
|
||||
DestroySwapImage();
|
||||
}
|
||||
|
||||
buffer_cache_.reset();
|
||||
|
@ -123,9 +130,15 @@ void VulkanCommandProcessor::MakeCoherent() {
|
|||
|
||||
CommandProcessor::MakeCoherent();
|
||||
|
||||
// Make region coherent
|
||||
if (status_host & 0x80000000ul) {
|
||||
// TODO(benvanik): less-fine-grained clearing.
|
||||
buffer_cache_->InvalidateCache();
|
||||
|
||||
if ((status_host & 0x01000000) != 0 && (status_host & 0x02000000) == 0) {
|
||||
coher_base_vc_ = regs->values[XE_GPU_REG_COHER_BASE_HOST].u32;
|
||||
coher_size_vc_ = regs->values[XE_GPU_REG_COHER_SIZE_HOST].u32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,8 +162,33 @@ void VulkanCommandProcessor::ReturnFromWait() {
|
|||
CommandProcessor::ReturnFromWait();
|
||||
}
|
||||
|
||||
void VulkanCommandProcessor::CreateSwapImages(VkCommandBuffer setup_buffer,
|
||||
VkExtent2D extents) {
|
||||
void VulkanCommandProcessor::WriteRegister(uint32_t index, uint32_t value) {
|
||||
CommandProcessor::WriteRegister(index, value);
|
||||
|
||||
if (index >= XE_GPU_REG_SHADER_CONSTANT_000_X &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_511_W) {
|
||||
uint32_t offset = index - XE_GPU_REG_SHADER_CONSTANT_000_X;
|
||||
offset /= 4 * 4;
|
||||
offset ^= 0x3F;
|
||||
|
||||
dirty_float_constants_ |= (1ull << offset);
|
||||
} else if (index >= XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031 &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_BOOL_224_255) {
|
||||
uint32_t offset = index - XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031;
|
||||
offset ^= 0x7;
|
||||
|
||||
dirty_bool_constants_ |= (1 << offset);
|
||||
} else if (index >= XE_GPU_REG_SHADER_CONSTANT_LOOP_00 &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_LOOP_31) {
|
||||
uint32_t offset = index - XE_GPU_REG_SHADER_CONSTANT_LOOP_00;
|
||||
offset ^= 0x1F;
|
||||
|
||||
dirty_loop_constants_ |= (1 << offset);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanCommandProcessor::CreateSwapImage(VkCommandBuffer setup_buffer,
|
||||
VkExtent2D extents) {
|
||||
VkImageCreateInfo image_info;
|
||||
std::memset(&image_info, 0, sizeof(VkImageCreateInfo));
|
||||
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
|
@ -168,34 +206,23 @@ void VulkanCommandProcessor::CreateSwapImages(VkCommandBuffer setup_buffer,
|
|||
image_info.pQueueFamilyIndices = nullptr;
|
||||
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VkImage image_fb, image_bb;
|
||||
VkImage image_fb;
|
||||
auto status = vkCreateImage(*device_, &image_info, nullptr, &image_fb);
|
||||
CheckResult(status, "vkCreateImage");
|
||||
|
||||
status = vkCreateImage(*device_, &image_info, nullptr, &image_bb);
|
||||
CheckResult(status, "vkCreateImage");
|
||||
|
||||
// Bind memory to images.
|
||||
// Bind memory to image.
|
||||
VkMemoryRequirements mem_requirements;
|
||||
vkGetImageMemoryRequirements(*device_, image_fb, &mem_requirements);
|
||||
fb_memory = device_->AllocateMemory(mem_requirements, 0);
|
||||
assert_not_null(fb_memory);
|
||||
fb_memory_ = device_->AllocateMemory(mem_requirements, 0);
|
||||
assert_not_null(fb_memory_);
|
||||
|
||||
status = vkBindImageMemory(*device_, image_fb, fb_memory, 0);
|
||||
CheckResult(status, "vkBindImageMemory");
|
||||
|
||||
vkGetImageMemoryRequirements(*device_, image_fb, &mem_requirements);
|
||||
bb_memory = device_->AllocateMemory(mem_requirements, 0);
|
||||
assert_not_null(bb_memory);
|
||||
|
||||
status = vkBindImageMemory(*device_, image_bb, bb_memory, 0);
|
||||
status = vkBindImageMemory(*device_, image_fb, fb_memory_, 0);
|
||||
CheckResult(status, "vkBindImageMemory");
|
||||
|
||||
std::lock_guard<std::mutex> lock(swap_state_.mutex);
|
||||
swap_state_.front_buffer_texture = reinterpret_cast<uintptr_t>(image_fb);
|
||||
swap_state_.back_buffer_texture = reinterpret_cast<uintptr_t>(image_bb);
|
||||
|
||||
// Transition both images to general layout.
|
||||
// Transition image to general layout.
|
||||
VkImageMemoryBarrier barrier;
|
||||
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
|
@ -208,32 +235,20 @@ void VulkanCommandProcessor::CreateSwapImages(VkCommandBuffer setup_buffer,
|
|||
barrier.image = image_fb;
|
||||
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
|
||||
vkCmdPipelineBarrier(setup_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||
nullptr, 1, &barrier);
|
||||
|
||||
barrier.image = image_bb;
|
||||
|
||||
vkCmdPipelineBarrier(setup_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||
nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
void VulkanCommandProcessor::DestroySwapImages() {
|
||||
void VulkanCommandProcessor::DestroySwapImage() {
|
||||
std::lock_guard<std::mutex> lock(swap_state_.mutex);
|
||||
vkDestroyImage(*device_,
|
||||
reinterpret_cast<VkImage>(swap_state_.front_buffer_texture),
|
||||
nullptr);
|
||||
vkDestroyImage(*device_,
|
||||
reinterpret_cast<VkImage>(swap_state_.back_buffer_texture),
|
||||
nullptr);
|
||||
vkFreeMemory(*device_, fb_memory, nullptr);
|
||||
vkFreeMemory(*device_, bb_memory, nullptr);
|
||||
vkFreeMemory(*device_, fb_memory_, nullptr);
|
||||
|
||||
swap_state_.front_buffer_texture = 0;
|
||||
swap_state_.back_buffer_texture = 0;
|
||||
fb_memory = nullptr;
|
||||
bb_memory = nullptr;
|
||||
fb_memory_ = nullptr;
|
||||
}
|
||||
|
||||
void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||
|
@ -267,10 +282,27 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
|||
frontbuffer_ptr = last_copy_base_;
|
||||
}
|
||||
|
||||
if (!swap_state_.back_buffer_texture) {
|
||||
CreateSwapImages(copy_commands, {frontbuffer_width, frontbuffer_height});
|
||||
if (!swap_state_.front_buffer_texture) {
|
||||
CreateSwapImage(copy_commands, {frontbuffer_width, frontbuffer_height});
|
||||
|
||||
// Signal the swap usage semaphore by default.
|
||||
auto swap_sem = reinterpret_cast<VkSemaphore>(swap_state_.backend_data);
|
||||
|
||||
VkSubmitInfo info;
|
||||
std::memset(&info, 0, sizeof(info));
|
||||
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
info.signalSemaphoreCount = 1;
|
||||
info.pSignalSemaphores = &swap_sem;
|
||||
if (queue_mutex_) {
|
||||
std::lock_guard<std::mutex> lock(*queue_mutex_);
|
||||
status = vkQueueSubmit(queue_, 1, &info, nullptr);
|
||||
CheckResult(status, "vkQueueSubmit");
|
||||
} else {
|
||||
status = vkQueueSubmit(queue_, 1, &info, nullptr);
|
||||
CheckResult(status, "vkQueueSubmit");
|
||||
}
|
||||
}
|
||||
auto swap_bb = reinterpret_cast<VkImage>(swap_state_.back_buffer_texture);
|
||||
auto swap_fb = reinterpret_cast<VkImage>(swap_state_.front_buffer_texture);
|
||||
|
||||
// Issue the commands to copy the game's frontbuffer to our backbuffer.
|
||||
auto texture = texture_cache_->LookupAddress(
|
||||
|
@ -310,7 +342,7 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
|||
int32_t(frontbuffer_height), 1};
|
||||
|
||||
vkCmdBlitImage(copy_commands, texture->image, texture->image_layout,
|
||||
swap_bb, VK_IMAGE_LAYOUT_GENERAL, 1, &blit,
|
||||
swap_fb, VK_IMAGE_LAYOUT_GENERAL, 1, &blit,
|
||||
VK_FILTER_LINEAR);
|
||||
|
||||
std::lock_guard<std::mutex> lock(swap_state_.mutex);
|
||||
|
@ -351,13 +383,28 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
|||
queue_mutex_->lock();
|
||||
}
|
||||
|
||||
// TODO: We really don't need to wrap all the commands with this semaphore,
|
||||
// only the copy commands.
|
||||
auto swap_sem = reinterpret_cast<VkSemaphore>(swap_state_.backend_data);
|
||||
|
||||
VkSubmitInfo submit_info;
|
||||
std::memset(&submit_info, 0, sizeof(VkSubmitInfo));
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.commandBufferCount = uint32_t(submit_buffers.size());
|
||||
submit_info.pCommandBuffers = submit_buffers.data();
|
||||
status = vkQueueSubmit(queue_, 1, &submit_info, *current_batch_fence_);
|
||||
CheckResult(status, "vkQueueSubmit");
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = &swap_sem;
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &swap_sem;
|
||||
|
||||
if (queue_mutex_) {
|
||||
std::lock_guard<std::mutex> lock(*queue_mutex_);
|
||||
status = vkQueueSubmit(queue_, 1, &submit_info, *current_batch_fence_);
|
||||
CheckResult(status, "vkQueueSubmit");
|
||||
} else {
|
||||
status = vkQueueSubmit(queue_, 1, &submit_info, *current_batch_fence_);
|
||||
CheckResult(status, "vkQueueSubmit");
|
||||
}
|
||||
|
||||
if (device_->is_renderdoc_attached() && capturing_) {
|
||||
device_->EndRenderDocFrameCapture();
|
||||
|
@ -370,6 +417,17 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
|||
|
||||
command_buffer_pool_->EndBatch(current_batch_fence_);
|
||||
|
||||
if (cache_clear_requested_) {
|
||||
cache_clear_requested_ = false;
|
||||
VkFence fences[] = {*current_batch_fence_};
|
||||
vkWaitForFences(*device_, 1, fences, VK_TRUE, -1);
|
||||
|
||||
buffer_cache_->ClearCache();
|
||||
pipeline_cache_->ClearCache();
|
||||
render_cache_->ClearCache();
|
||||
texture_cache_->ClearCache();
|
||||
}
|
||||
|
||||
// Scavenging.
|
||||
{
|
||||
#if FINE_GRAINED_DRAW_SCOPES
|
||||
|
@ -492,10 +550,6 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
|||
current_render_state_ = render_cache_->BeginRenderPass(
|
||||
command_buffer, vertex_shader, pixel_shader);
|
||||
if (!current_render_state_) {
|
||||
command_buffer_pool_->CancelBatch();
|
||||
current_command_buffer_ = nullptr;
|
||||
current_setup_buffer_ = nullptr;
|
||||
current_batch_fence_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -512,46 +566,22 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
|||
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipeline);
|
||||
} else if (pipeline_status == PipelineCache::UpdateStatus::kError) {
|
||||
render_cache_->EndRenderPass();
|
||||
command_buffer_pool_->CancelBatch();
|
||||
current_command_buffer_ = nullptr;
|
||||
current_setup_buffer_ = nullptr;
|
||||
current_batch_fence_ = nullptr;
|
||||
current_render_state_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
pipeline_cache_->SetDynamicState(command_buffer, started_command_buffer);
|
||||
|
||||
// Pass registers to the shaders.
|
||||
if (!PopulateConstants(command_buffer, vertex_shader, pixel_shader)) {
|
||||
render_cache_->EndRenderPass();
|
||||
command_buffer_pool_->CancelBatch();
|
||||
current_command_buffer_ = nullptr;
|
||||
current_setup_buffer_ = nullptr;
|
||||
current_batch_fence_ = nullptr;
|
||||
current_render_state_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Upload and bind index buffer data (if we have any).
|
||||
if (!PopulateIndexBuffer(command_buffer, index_buffer_info)) {
|
||||
render_cache_->EndRenderPass();
|
||||
command_buffer_pool_->CancelBatch();
|
||||
current_command_buffer_ = nullptr;
|
||||
current_setup_buffer_ = nullptr;
|
||||
current_batch_fence_ = nullptr;
|
||||
current_render_state_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Upload and bind all vertex buffer data.
|
||||
if (!PopulateVertexBuffers(command_buffer, vertex_shader)) {
|
||||
render_cache_->EndRenderPass();
|
||||
command_buffer_pool_->CancelBatch();
|
||||
current_command_buffer_ = nullptr;
|
||||
current_setup_buffer_ = nullptr;
|
||||
current_batch_fence_ = nullptr;
|
||||
current_render_state_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -560,12 +590,6 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
|||
// Setup buffer may be flushed to GPU if the texture cache needs it.
|
||||
if (!PopulateSamplers(command_buffer, setup_buffer, vertex_shader,
|
||||
pixel_shader)) {
|
||||
render_cache_->EndRenderPass();
|
||||
command_buffer_pool_->CancelBatch();
|
||||
current_command_buffer_ = nullptr;
|
||||
current_setup_buffer_ = nullptr;
|
||||
current_batch_fence_ = nullptr;
|
||||
current_render_state_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -719,11 +743,12 @@ bool VulkanCommandProcessor::PopulateVertexBuffers(
|
|||
// THIS CAN BE MASSIVELY INCORRECT (too large).
|
||||
size_t valid_range = size_t(fetch->size * 4);
|
||||
|
||||
trace_writer_.WriteMemoryRead(fetch->address << 2, valid_range);
|
||||
uint32_t physical_address = fetch->address << 2;
|
||||
trace_writer_.WriteMemoryRead(physical_address, valid_range);
|
||||
|
||||
// Upload (or get a cached copy of) the buffer.
|
||||
const void* source_ptr =
|
||||
memory_->TranslatePhysical<const void*>(fetch->address << 2);
|
||||
memory_->TranslatePhysical<const void*>(physical_address);
|
||||
size_t source_length = valid_range;
|
||||
auto buffer_ref = buffer_cache_->UploadVertexBuffer(
|
||||
source_ptr, source_length, static_cast<Endian>(fetch->endian),
|
||||
|
|
|
@ -62,8 +62,10 @@ class VulkanCommandProcessor : public CommandProcessor {
|
|||
void PrepareForWait() override;
|
||||
void ReturnFromWait() override;
|
||||
|
||||
void CreateSwapImages(VkCommandBuffer setup_buffer, VkExtent2D extents);
|
||||
void DestroySwapImages();
|
||||
void WriteRegister(uint32_t index, uint32_t value) override;
|
||||
|
||||
void CreateSwapImage(VkCommandBuffer setup_buffer, VkExtent2D extents);
|
||||
void DestroySwapImage();
|
||||
|
||||
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
|
||||
uint32_t frontbuffer_height) override;
|
||||
|
@ -90,8 +92,14 @@ class VulkanCommandProcessor : public CommandProcessor {
|
|||
xe::ui::vulkan::VulkanDevice* device_ = nullptr;
|
||||
|
||||
// front buffer / back buffer memory
|
||||
VkDeviceMemory fb_memory = nullptr;
|
||||
VkDeviceMemory bb_memory = nullptr;
|
||||
VkDeviceMemory fb_memory_ = nullptr;
|
||||
|
||||
uint64_t dirty_float_constants_ = 0; // Dirty float constants in blocks of 4
|
||||
uint8_t dirty_bool_constants_ = 0;
|
||||
uint32_t dirty_loop_constants_ = 0;
|
||||
|
||||
uint32_t coher_base_vc_ = 0;
|
||||
uint32_t coher_size_vc_ = 0;
|
||||
|
||||
// TODO(benvanik): abstract behind context?
|
||||
// Queue used to submit work. This may be a dedicated queue for the command
|
||||
|
@ -103,8 +111,10 @@ class VulkanCommandProcessor : public CommandProcessor {
|
|||
|
||||
// Last copy base address, for debugging only.
|
||||
uint32_t last_copy_base_ = 0;
|
||||
|
||||
bool capturing_ = false;
|
||||
bool trace_requested_ = false;
|
||||
bool cache_clear_requested_ = false;
|
||||
|
||||
std::unique_ptr<BufferCache> buffer_cache_;
|
||||
std::unique_ptr<PipelineCache> pipeline_cache_;
|
||||
|
|
|
@ -64,8 +64,6 @@ void VulkanGraphicsSystem::Swap(xe::ui::UIEvent* e) {
|
|||
std::lock_guard<std::mutex> lock(swap_state.mutex);
|
||||
if (swap_state.pending) {
|
||||
swap_state.pending = false;
|
||||
std::swap(swap_state.front_buffer_texture,
|
||||
swap_state.back_buffer_texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,11 +72,17 @@ void VulkanGraphicsSystem::Swap(xe::ui::UIEvent* e) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto semaphore = reinterpret_cast<VkSemaphore>(swap_state.backend_data);
|
||||
auto swap_chain = display_context_->swap_chain();
|
||||
auto copy_cmd_buffer = swap_chain->copy_cmd_buffer();
|
||||
auto front_buffer =
|
||||
reinterpret_cast<VkImage>(swap_state.front_buffer_texture);
|
||||
|
||||
// Wait on and signal the swap semaphore.
|
||||
// TODO(DrChat): Interacting with the window causes the device to be lost in
|
||||
// some games.
|
||||
// swap_chain->WaitAndSignalSemaphore(semaphore);
|
||||
|
||||
VkImageMemoryBarrier barrier;
|
||||
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
|
|
|
@ -338,6 +338,10 @@ bool VulkanSwapChain::Reinitialize() {
|
|||
return Initialize(surface);
|
||||
}
|
||||
|
||||
void VulkanSwapChain::WaitAndSignalSemaphore(VkSemaphore sem) {
|
||||
wait_and_signal_semaphores_.push_back(sem);
|
||||
}
|
||||
|
||||
void VulkanSwapChain::Shutdown() {
|
||||
// TODO(benvanik): properly wait for a clean state.
|
||||
for (auto& buffer : buffers_) {
|
||||
|
@ -372,6 +376,8 @@ void VulkanSwapChain::Shutdown() {
|
|||
}
|
||||
|
||||
bool VulkanSwapChain::Begin() {
|
||||
wait_and_signal_semaphores_.clear();
|
||||
|
||||
// Get the index of the next available swapchain image.
|
||||
auto err =
|
||||
vkAcquireNextImageKHR(*device_, handle, 0, image_available_semaphore_,
|
||||
|
@ -521,28 +527,34 @@ bool VulkanSwapChain::End() {
|
|||
|
||||
VkPipelineStageFlags wait_dst_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
|
||||
std::vector<VkSemaphore> semaphores;
|
||||
for (size_t i = 0; i < wait_and_signal_semaphores_.size(); i++) {
|
||||
semaphores.push_back(wait_and_signal_semaphores_[i]);
|
||||
}
|
||||
semaphores.push_back(image_usage_semaphore_);
|
||||
|
||||
// Submit copy commands.
|
||||
// Wait on the image usage semaphore (signaled when an image is available)
|
||||
VkSubmitInfo render_submit_info;
|
||||
render_submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
render_submit_info.pNext = nullptr;
|
||||
render_submit_info.waitSemaphoreCount = 1;
|
||||
render_submit_info.pWaitSemaphores = &image_usage_semaphore_;
|
||||
render_submit_info.waitSemaphoreCount = uint32_t(semaphores.size());
|
||||
render_submit_info.pWaitSemaphores = semaphores.data();
|
||||
render_submit_info.pWaitDstStageMask = &wait_dst_stage;
|
||||
render_submit_info.commandBufferCount = 1;
|
||||
render_submit_info.pCommandBuffers = ©_cmd_buffer_;
|
||||
render_submit_info.signalSemaphoreCount = 1;
|
||||
render_submit_info.pSignalSemaphores = &image_usage_semaphore_;
|
||||
render_submit_info.signalSemaphoreCount = uint32_t(semaphores.size());
|
||||
render_submit_info.pSignalSemaphores = semaphores.data();
|
||||
{
|
||||
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
|
||||
err = vkQueueSubmit(device_->primary_queue(), 1, &render_submit_info,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// Submit render commands.
|
||||
// Submit render commands, and don't signal the usage semaphore.
|
||||
render_submit_info.commandBufferCount = 1;
|
||||
render_submit_info.pCommandBuffers = &render_cmd_buffer_;
|
||||
render_submit_info.signalSemaphoreCount = 0;
|
||||
render_submit_info.pSignalSemaphores = nullptr;
|
||||
render_submit_info.signalSemaphoreCount = uint32_t(semaphores.size()) - 1;
|
||||
{
|
||||
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
|
||||
err = vkQueueSubmit(device_->primary_queue(), 1, &render_submit_info,
|
||||
|
|
|
@ -53,6 +53,9 @@ class VulkanSwapChain {
|
|||
// torn down and recreated with the new surface properties (size/etc).
|
||||
bool Reinitialize();
|
||||
|
||||
// Waits on and signals a semaphore in this operation.
|
||||
void WaitAndSignalSemaphore(VkSemaphore sem);
|
||||
|
||||
// Begins the swap operation, preparing state for rendering.
|
||||
bool Begin();
|
||||
// Ends the swap operation, finalizing rendering and presenting the results.
|
||||
|
@ -86,6 +89,7 @@ class VulkanSwapChain {
|
|||
VkSemaphore image_usage_semaphore_ = nullptr;
|
||||
uint32_t current_buffer_index_ = 0;
|
||||
std::vector<Buffer> buffers_;
|
||||
std::vector<VkSemaphore> wait_and_signal_semaphores_;
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
|
|
Loading…
Reference in New Issue