diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 80853362ad..de854554c7 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -189,7 +189,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat frame->image = memory_allocator.CreateImage({ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, - .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, + .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, .imageType = VK_IMAGE_TYPE_2D, .format = swapchain.GetImageFormat(), .extent = diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 281983168e..30ac002ef6 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -665,6 +665,7 @@ public: offsets.fill(0); last_queries.fill(0); last_queries_stride.fill(1); + stream_to_slot.fill(INVALID_SLOT); VkBufferUsageFlags counter_buffer_usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; if (device.IsExtTransformFeedbackSupported()) { @@ -773,15 +774,24 @@ public: return index; } const size_t subreport = static_cast(*subreport_); + if (subreport >= NUM_STREAMS) { + new_query->flags |= VideoCommon::QueryFlagBits::IsFinalValueSynced; + return index; + } last_queries[subreport] = address; if ((streams_mask & (1ULL << subreport)) == 0) { new_query->flags |= VideoCommon::QueryFlagBits::IsFinalValueSynced; return index; } + const size_t slot = stream_to_slot[subreport]; + if (slot >= NUM_STREAMS) { + new_query->flags |= VideoCommon::QueryFlagBits::IsFinalValueSynced; + return index; + } scheduler.RequestOutsideRenderPassOperationContext(); CloseCounter(); - auto [bank_slot, data_slot] = ProduceCounterBuffer(subreport); + auto [bank_slot, data_slot] = ProduceCounterBuffer(slot); new_query->start_bank_id = static_cast(bank_slot); new_query->size_banks = 1; new_query->start_slot = static_cast(data_slot); @@ -792,6 +802,9 @@ public: } std::optional> GetLastQueryStream(size_t stream) { + if (stream >= NUM_STREAMS) { + return std::nullopt; + } if (last_queries[stream] != 0) { std::pair result(last_queries[stream], last_queries_stride[stream]); return result; @@ -932,6 +945,7 @@ private: void UpdateBuffers() { last_queries.fill(0); last_queries_stride.fill(1); + stream_to_slot.fill(INVALID_SLOT); streams_mask = 0; // reset previously recorded streams runtime.View3DRegs([this](Maxwell3D& maxwell3d) { buffers_count = 0; @@ -956,19 +970,23 @@ private: if (tf.buffers[i].enable == 0) { continue; } + buffers_count = std::max(buffers_count, i + 1); const size_t stream = tf.controls[i].stream; if (stream >= last_queries_stride.size()) { LOG_WARNING(Render_Vulkan, "TransformFeedback stream {} out of range", stream); continue; } + if ((streams_mask & (1ULL << stream)) != 0) { + continue; + } last_queries_stride[stream] = tf.controls[i].stride; + stream_to_slot[stream] = i; streams_mask |= 1ULL << stream; - buffers_count = std::max(buffers_count, stream + 1); } }); } - std::pair ProduceCounterBuffer(size_t stream) { + std::pair ProduceCounterBuffer(size_t slot_index) { if (current_bank == nullptr || current_bank->IsClosed()) { current_bank_id = bank_pool.ReserveBank([this](std::deque& queue, size_t index) { @@ -994,7 +1012,8 @@ private: }; scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([dst_buffer = current_bank->GetBuffer(), - src_buffer = counter_buffers[stream], src_offset = offsets[stream], + src_buffer = counter_buffers[slot_index], + src_offset = offsets[slot_index], slot](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER); @@ -1013,6 +1032,7 @@ private: friend class PrimitivesSucceededStreamer; static constexpr size_t NUM_STREAMS = 4; + static constexpr size_t INVALID_SLOT = NUM_STREAMS; QueryCacheRuntime& runtime; const Device& device; @@ -1042,6 +1062,7 @@ private: std::array offsets{}; std::array last_queries; std::array last_queries_stride; + std::array stream_to_slot; Maxwell3D::Regs::PrimitiveTopology out_topology; u32 patch_vertices{1}; u64 streams_mask; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 2dbaab4127..534587ee94 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -176,7 +176,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { .pViewFormats = view_formats.data(), }; if (view_formats.size() > 1) { - image_ci.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + image_ci.flags |= + VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; if (device.IsKhrImageFormatListSupported()) { image_ci.pNext = &image_format_list; }