diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.cc b/src/xenia/gpu/vulkan/vulkan_command_processor.cc index 0e87dcfb9..3529b59cd 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.cc @@ -251,6 +251,69 @@ void VulkanCommandProcessor::DestroySwapImage() { fb_memory_ = nullptr; } +void VulkanCommandProcessor::BeginFrame() { + assert_false(frame_open_); + + // TODO(benvanik): bigger batches. + // TODO(DrChat): Decouple setup buffer from current batch. + // Begin a new batch, and allocate and begin a command buffer and setup buffer. + current_batch_fence_ = command_buffer_pool_->BeginBatch(); + current_command_buffer_ = command_buffer_pool_->AcquireEntry(); + current_setup_buffer_ = command_buffer_pool_->AcquireEntry(); + + VkCommandBufferBeginInfo command_buffer_begin_info; + command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + command_buffer_begin_info.pNext = nullptr; + command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + command_buffer_begin_info.pInheritanceInfo = nullptr; + auto status = + vkBeginCommandBuffer(current_command_buffer_, &command_buffer_begin_info); + CheckResult(status, "vkBeginCommandBuffer"); + + status = + vkBeginCommandBuffer(current_setup_buffer_, &command_buffer_begin_info); + CheckResult(status, "vkBeginCommandBuffer"); + + // Flag renderdoc down to start a capture if requested. + // The capture will end when these commands are submitted to the queue. + static uint32_t frame = 0; + if (device_->is_renderdoc_attached() && !capturing_ && + (FLAGS_vulkan_renderdoc_capture_all || trace_requested_)) { + if (queue_mutex_) { + queue_mutex_->lock(); + } + + capturing_ = true; + trace_requested_ = false; + device_->BeginRenderDocFrameCapture(); + + if (queue_mutex_) { + queue_mutex_->unlock(); + } + } + + frame_open_ = true; +} + +void VulkanCommandProcessor::EndFrame() { + if (current_render_state_) { + render_cache_->EndRenderPass(); + current_render_state_ = nullptr; + } + + VkResult status = VK_SUCCESS; + status = vkEndCommandBuffer(current_setup_buffer_); + CheckResult(status, "vkEndCommandBuffer"); + status = vkEndCommandBuffer(current_command_buffer_); + CheckResult(status, "vkEndCommandBuffer"); + + current_command_buffer_ = nullptr; + current_setup_buffer_ = nullptr; + command_buffer_pool_->EndBatch(); + + frame_open_ = false; +} + void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width, uint32_t frontbuffer_height) { @@ -355,23 +418,15 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, // Queue up current command buffers. // TODO(benvanik): bigger batches. std::vector submit_buffers; - if (current_command_buffer_) { - if (current_render_state_) { - render_cache_->EndRenderPass(); - current_render_state_ = nullptr; - } - - status = vkEndCommandBuffer(current_setup_buffer_); - CheckResult(status, "vkEndCommandBuffer"); - status = vkEndCommandBuffer(current_command_buffer_); - CheckResult(status, "vkEndCommandBuffer"); - + if (frame_open_) { // TODO(DrChat): If the setup buffer is empty, don't bother queueing it up. submit_buffers.push_back(current_setup_buffer_); submit_buffers.push_back(current_command_buffer_); + EndFrame(); + } - current_command_buffer_ = nullptr; - current_setup_buffer_ = nullptr; + if (opened_batch) { + command_buffer_pool_->EndBatch(); } submit_buffers.push_back(copy_commands); @@ -413,8 +468,6 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, } } - command_buffer_pool_->EndBatch(); - if (cache_clear_requested_) { cache_clear_requested_ = false; vkWaitForFences(*device_, 1, ¤t_batch_fence_, VK_TRUE, -1); @@ -493,46 +546,10 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type, return true; } - bool started_command_buffer = false; - if (!current_command_buffer_) { - // TODO(benvanik): bigger batches. - // TODO(DrChat): Decouple setup buffer from current batch. - current_batch_fence_ = command_buffer_pool_->BeginBatch(); - current_command_buffer_ = command_buffer_pool_->AcquireEntry(); - current_setup_buffer_ = command_buffer_pool_->AcquireEntry(); - - VkCommandBufferBeginInfo command_buffer_begin_info; - command_buffer_begin_info.sType = - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - command_buffer_begin_info.pNext = nullptr; - command_buffer_begin_info.flags = - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - command_buffer_begin_info.pInheritanceInfo = nullptr; - auto status = vkBeginCommandBuffer(current_command_buffer_, - &command_buffer_begin_info); - CheckResult(status, "vkBeginCommandBuffer"); - - status = - vkBeginCommandBuffer(current_setup_buffer_, &command_buffer_begin_info); - CheckResult(status, "vkBeginCommandBuffer"); - - static uint32_t frame = 0; - if (device_->is_renderdoc_attached() && !capturing_ && - (FLAGS_vulkan_renderdoc_capture_all || trace_requested_)) { - if (queue_mutex_) { - queue_mutex_->lock(); - } - - capturing_ = true; - trace_requested_ = false; - device_->BeginRenderDocFrameCapture(); - - if (queue_mutex_) { - queue_mutex_->unlock(); - } - } - - started_command_buffer = true; + bool started_frame = false; + if (!frame_open_) { + BeginFrame(); + started_frame = true; } auto command_buffer = current_command_buffer_; auto setup_buffer = current_setup_buffer_; @@ -561,13 +578,13 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type, command_buffer, current_render_state_, vertex_shader, pixel_shader, primitive_type, &pipeline); if (pipeline_status == PipelineCache::UpdateStatus::kMismatch || - started_command_buffer) { + started_frame) { vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); } else if (pipeline_status == PipelineCache::UpdateStatus::kError) { return false; } - pipeline_cache_->SetDynamicState(command_buffer, started_command_buffer); + pipeline_cache_->SetDynamicState(command_buffer, started_frame); // Pass registers to the shaders. if (!PopulateConstants(command_buffer, vertex_shader, pixel_shader)) { @@ -899,26 +916,23 @@ bool VulkanCommandProcessor::IssueCopy() { assert_true(fetch->size == 6); const uint8_t* vertex_addr = memory_->TranslatePhysical(fetch->address << 2); trace_writer_.WriteMemoryRead(fetch->address << 2, fetch->size * 4); - int32_t dest_min_x = int32_t((std::min( - std::min( - GpuSwap(xe::load(vertex_addr + 0), Endian(fetch->endian)), - GpuSwap(xe::load(vertex_addr + 8), Endian(fetch->endian))), - GpuSwap(xe::load(vertex_addr + 16), Endian(fetch->endian))))); - int32_t dest_max_x = int32_t((std::max( - std::max( - GpuSwap(xe::load(vertex_addr + 0), Endian(fetch->endian)), - GpuSwap(xe::load(vertex_addr + 8), Endian(fetch->endian))), - GpuSwap(xe::load(vertex_addr + 16), Endian(fetch->endian))))); - int32_t dest_min_y = int32_t((std::min( - std::min( - GpuSwap(xe::load(vertex_addr + 4), Endian(fetch->endian)), - GpuSwap(xe::load(vertex_addr + 12), Endian(fetch->endian))), - GpuSwap(xe::load(vertex_addr + 20), Endian(fetch->endian))))); - int32_t dest_max_y = int32_t((std::max( - std::max( - GpuSwap(xe::load(vertex_addr + 4), Endian(fetch->endian)), - GpuSwap(xe::load(vertex_addr + 12), Endian(fetch->endian))), - GpuSwap(xe::load(vertex_addr + 20), Endian(fetch->endian))))); + + float dest_points[6]; + for (int i = 0; i < 6; i++) { + dest_points[i] = + GpuSwap(xe::load(vertex_addr + i * 4), Endian(fetch->endian)); + } + + // Note: The xenos only supports rectangle copies (luckily) + int32_t dest_min_x = int32_t( + (std::min(std::min(dest_points[0], dest_points[2]), dest_points[4]))); + int32_t dest_max_x = int32_t( + (std::max(std::max(dest_points[0], dest_points[2]), dest_points[4]))); + + int32_t dest_min_y = int32_t( + (std::min(std::min(dest_points[1], dest_points[3]), dest_points[5]))); + int32_t dest_max_y = int32_t( + (std::max(std::max(dest_points[1], dest_points[3]), dest_points[5]))); uint32_t color_edram_base = 0; uint32_t depth_edram_base = 0; @@ -972,26 +986,10 @@ bool VulkanCommandProcessor::IssueCopy() { // For debugging purposes only (trace viewer) last_copy_base_ = texture->texture_info.guest_address; - if (!current_command_buffer_) { - current_batch_fence_ = command_buffer_pool_->BeginBatch(); - current_command_buffer_ = command_buffer_pool_->AcquireEntry(); - current_setup_buffer_ = command_buffer_pool_->AcquireEntry(); - - VkCommandBufferBeginInfo command_buffer_begin_info; - command_buffer_begin_info.sType = - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - command_buffer_begin_info.pNext = nullptr; - command_buffer_begin_info.flags = - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - command_buffer_begin_info.pInheritanceInfo = nullptr; - auto status = vkBeginCommandBuffer(current_command_buffer_, - &command_buffer_begin_info); - CheckResult(status, "vkBeginCommandBuffer"); - - status = - vkBeginCommandBuffer(current_setup_buffer_, &command_buffer_begin_info); - CheckResult(status, "vkBeginCommandBuffer"); + if (!frame_open_) { + BeginFrame(); } else if (current_render_state_) { + // Copy commands cannot be issued within a render pass. render_cache_->EndRenderPass(); current_render_state_ = nullptr; } diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.h b/src/xenia/gpu/vulkan/vulkan_command_processor.h index 17daf3c4c..79f1bfdd9 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.h +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.h @@ -64,6 +64,9 @@ class VulkanCommandProcessor : public CommandProcessor { void WriteRegister(uint32_t index, uint32_t value) override; + void BeginFrame(); + void EndFrame(); + void CreateSwapImage(VkCommandBuffer setup_buffer, VkExtent2D extents); void DestroySwapImage(); @@ -123,6 +126,7 @@ class VulkanCommandProcessor : public CommandProcessor { std::unique_ptr command_buffer_pool_; + bool frame_open_ = false; const RenderState* current_render_state_ = nullptr; VkCommandBuffer current_command_buffer_ = nullptr; VkCommandBuffer current_setup_buffer_ = nullptr;