From 88f0014bc744e7a689df8ef846ad748556b320bd Mon Sep 17 00:00:00 2001 From: Kelebek1 Date: Mon, 13 Mar 2023 21:47:24 +0000 Subject: [PATCH] Implement transform feedback queries and draws. --- src/common/settings.cpp | 2 + src/common/settings.h | 1 + src/core/telemetry_session.cpp | 2 + src/video_core/engines/maxwell_3d.cpp | 16 ++++ src/video_core/macro/macro_hle.cpp | 24 ++++++ src/video_core/rasterizer_interface.h | 2 + .../renderer_null/null_rasterizer.cpp | 3 + .../renderer_null/null_rasterizer.h | 1 + .../renderer_opengl/gl_rasterizer.cpp | 69 ++++++++++++---- .../renderer_opengl/gl_rasterizer.h | 7 +- .../renderer_vulkan/vk_buffer_cache.cpp | 16 ++++ .../renderer_vulkan/vk_buffer_cache.h | 4 +- .../renderer_vulkan/vk_rasterizer.cpp | 67 +++++++++++---- .../renderer_vulkan/vk_rasterizer.h | 5 ++ .../vulkan_common/vulkan_wrapper.cpp | 1 + src/video_core/vulkan_common/vulkan_wrapper.h | 8 ++ src/yuzu/configuration/config.cpp | 2 + .../configure_graphics_advanced.cpp | 10 +++ .../configure_graphics_advanced.h | 1 + .../configure_graphics_advanced.ui | 82 +++++++++++-------- 20 files changed, 252 insertions(+), 71 deletions(-) diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 5972480e51..ebcdfd7965 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -82,6 +82,7 @@ void LogSettings() { values.use_asynchronous_gpu_emulation.GetValue()); log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue()); log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue()); + log_setting("Renderer_TransformFeedbackQuery", values.transform_feedback_query.GetValue()); log_setting("Renderer_AsyncASTC", values.async_astc.GetValue()); log_setting("Renderer_AstcRecompression", values.astc_recompression.GetValue()); log_setting("Renderer_UseVsync", values.vsync_mode.GetValue()); @@ -246,6 +247,7 @@ void RestoreGlobalState(bool is_powered_on) { values.use_asynchronous_gpu_emulation.SetGlobal(true); values.nvdec_emulation.SetGlobal(true); values.accelerate_astc.SetGlobal(true); + values.transform_feedback_query.SetGlobal(true); values.async_astc.SetGlobal(true); values.astc_recompression.SetGlobal(true); values.use_reactive_flushing.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index 59e96e74fd..70fb8d8697 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -468,6 +468,7 @@ struct Values { SwitchableSetting use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"}; SwitchableSetting nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; SwitchableSetting accelerate_astc{true, "accelerate_astc"}; + SwitchableSetting transform_feedback_query{false, "transform_feedback_query"}; SwitchableSetting async_astc{false, "async_astc"}; Setting vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate, VSyncMode::FIFORelaxed, "use_vsync"}; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 7a2f3c90af..cbc417bd23 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -255,6 +255,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, AddField(field_type, "Renderer_NvdecEmulation", TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue())); AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue()); + AddField(field_type, "Renderer_TransformFeedbackQuery", + Settings::values.transform_feedback_query.GetValue()); AddField(field_type, "Renderer_UseVsync", TranslateVSyncMode(Settings::values.vsync_mode.GetValue())); AddField(field_type, "Renderer_ShaderBackend", diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index c3696096d3..dda4da45ee 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -631,6 +631,22 @@ std::optional Maxwell3D::GetQueryResult() { rasterizer->Query(regs.report_semaphore.Address(), QueryType::SamplesPassed, system.GPU().GetTicks()); return std::nullopt; + case Regs::ReportSemaphore::Report::StreamingPrimitivesSucceeded: + if (Settings::values.transform_feedback_query) { + if (regs.report_semaphore.query.sub_report == 0) { + ASSERT(regs.transform_feedback.controls[0].stride != 0); + return rasterizer->GetTransformFeedbackByteCount() / + regs.transform_feedback.controls[0].stride; + } + } + return 0; + case Regs::ReportSemaphore::Report::StreamingByteCount: + if (Settings::values.transform_feedback_query) { + if (regs.report_semaphore.query.sub_report == 0) { + return rasterizer->GetTransformFeedbackByteCount(); + } + } + return 0; default: LOG_DEBUG(HW_GPU, "Unimplemented query report type {}", regs.report_semaphore.query.report.Value()); diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 6272a4652e..8721ef4405 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp @@ -462,6 +462,25 @@ public: } }; +class HLE_B5F74EDB717278EC final : public HLEMacroImpl { +public: + explicit HLE_B5F74EDB717278EC(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} + + void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { + maxwell3d.RefreshParameters(); + + maxwell3d.regs.draw.begin = parameters[0]; + maxwell3d.regs.draw_auto_stride = parameters[1]; + maxwell3d.regs.draw_auto_byte_count = parameters[2]; + + if (maxwell3d.ShouldExecute()) { + maxwell3d.draw_manager->DrawArray( + maxwell3d.regs.draw.topology, 0, + maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1); + } + } +}; + } // Anonymous namespace HLEMacro::HLEMacro(Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} { @@ -536,6 +555,11 @@ HLEMacro::HLEMacro(Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} { [](Maxwell3D& maxwell3d__) -> std::unique_ptr { return std::make_unique(maxwell3d__); })); + builders.emplace(0xB5F74EDB717278ECULL, + std::function(Maxwell3D&)>( + [](Maxwell3D& maxwell3d__) -> std::unique_ptr { + return std::make_unique(maxwell3d__); + })); } HLEMacro::~HLEMacro() = default; diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index cb8029a4fc..749d7fb2f2 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -176,5 +176,7 @@ public: virtual void BindChannel(Tegra::Control::ChannelState& channel) {} virtual void ReleaseChannel(s32 channel_id) {} + + virtual u32 GetTransformFeedbackByteCount() = 0; }; } // namespace VideoCore diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp index 92ecf6682f..6e876ee40e 100644 --- a/src/video_core/renderer_null/null_rasterizer.cpp +++ b/src/video_core/renderer_null/null_rasterizer.cpp @@ -100,5 +100,8 @@ void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loadin void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) {} void RasterizerNull::BindChannel(Tegra::Control::ChannelState& channel) {} void RasterizerNull::ReleaseChannel(s32 channel_id) {} +u32 RasterizerNull::GetTransformFeedbackByteCount() { + return 0; +} } // namespace Null diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h index 93b9a69714..90fe0472cd 100644 --- a/src/video_core/renderer_null/null_rasterizer.h +++ b/src/video_core/renderer_null/null_rasterizer.h @@ -84,6 +84,7 @@ public: void InitializeChannel(Tegra::Control::ChannelState& channel) override; void BindChannel(Tegra::Control::ChannelState& channel) override; void ReleaseChannel(s32 channel_id) override; + u32 GetTransformFeedbackByteCount() override; private: Tegra::GPU& m_gpu; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index aadd6967c5..7548f24050 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -67,9 +67,13 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra state_tracker, gpu.ShaderNotify()), query_cache(*this, cpu_memory_), accelerate_dma(buffer_cache, texture_cache), fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache), - blit_image(program_manager_) {} + blit_image(program_manager_) { + glGenQueries(1, &transform_query); +} -RasterizerOpenGL::~RasterizerOpenGL() = default; +RasterizerOpenGL::~RasterizerOpenGL() { + glDeleteQueries(1, &transform_query); +} void RasterizerOpenGL::SyncVertexFormats() { auto& flags = maxwell3d->dirty.flags; @@ -233,12 +237,15 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(draw_state.topology); - BeginTransformFeedback(pipeline, primitive_mode); + + if (host_tfb_enabled && !maxwell3d->regs.transform_feedback_enabled) { + EndTransformFeedback(); + } else { + BeginTransformFeedback(pipeline, primitive_mode); + } draw_func(primitive_mode); - EndTransformFeedback(); - ++num_queued_commands; has_written_global_memory |= pipeline->WritesGlobalMemory(); } @@ -1251,27 +1258,44 @@ void RasterizerOpenGL::SyncFramebufferSRGB() { void RasterizerOpenGL::BeginTransformFeedback(GraphicsPipeline* program, GLenum primitive_mode) { const auto& regs = maxwell3d->regs; - if (regs.transform_feedback_enabled == 0) { + UNIMPLEMENTED_IF(maxwell3d->regs.IsShaderConfigEnabled(Maxwell::ShaderType::TessellationInit) || + maxwell3d->regs.IsShaderConfigEnabled(Maxwell::ShaderType::Tessellation)); + + if (host_tfb_enabled) { + prev_tfb_enabled = regs.transform_feedback_enabled; return; } + program->ConfigureTransformFeedback(); - UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderType::TessellationInit) || - regs.IsShaderConfigEnabled(Maxwell::ShaderType::Tessellation) || - regs.IsShaderConfigEnabled(Maxwell::ShaderType::Geometry)); - UNIMPLEMENTED_IF(primitive_mode != GL_POINTS); - - // We may have to call BeginTransformFeedbackNV here since they seem to call different - // implementations on Nvidia's driver (the pointer is different) but we are using - // ARB_transform_feedback3 features with NV_transform_feedback interactions and the ARB - // extension doesn't define BeginTransformFeedback (without NV) interactions. It just works. - glBeginTransformFeedback(GL_POINTS); + if (regs.transform_feedback_enabled && prev_tfb_enabled) { + // if current and previous tfbs are enabled, we're resuming. + glResumeTransformFeedback(); + host_tfb_enabled = true; + } else if (regs.transform_feedback_enabled) { + UNIMPLEMENTED_IF(primitive_mode != GL_POINTS); + // We may have to call BeginTransformFeedbackNV here since they seem to call different + // implementations on Nvidia's driver (the pointer is different) but we are using + // ARB_transform_feedback3 features with NV_transform_feedback interactions and the ARB + // extension doesn't define BeginTransformFeedback (without NV) interactions. It just works. + glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, transform_query); + glBeginTransformFeedback(GL_POINTS); + host_tfb_enabled = true; + } + prev_tfb_enabled = regs.transform_feedback_enabled; } -void RasterizerOpenGL::EndTransformFeedback() { - if (maxwell3d->regs.transform_feedback_enabled != 0) { +void RasterizerOpenGL::EndTransformFeedback(bool force) { + if (!force && host_tfb_enabled && maxwell3d->regs.transform_feedback_enabled) { + // guest is still active, so pause + glPauseTransformFeedback(); + host_tfb_enabled = false; + } else if (host_tfb_enabled) { glEndTransformFeedback(); + glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); + host_tfb_enabled = false; } + prev_tfb_enabled = maxwell3d->regs.transform_feedback_enabled; } void RasterizerOpenGL::InitializeChannel(Tegra::Control::ChannelState& channel) { @@ -1311,6 +1335,15 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) { query_cache.EraseChannel(channel_id); } +u32 RasterizerOpenGL::GetTransformFeedbackByteCount() { + EndTransformFeedback(true); + + GLuint count{}; + glGetQueryObjectuiv(transform_query, GL_QUERY_RESULT, &count); + + return count * maxwell3d->regs.transform_feedback.controls[0].stride; +} + AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_) : buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {} diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 8eda2ddba6..c13765846a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -138,6 +138,8 @@ public: void ReleaseChannel(s32 channel_id) override; + u32 GetTransformFeedbackByteCount() override; + private: static constexpr size_t MAX_TEXTURES = 192; static constexpr size_t MAX_IMAGES = 48; @@ -222,7 +224,7 @@ private: void BeginTransformFeedback(GraphicsPipeline* pipeline, GLenum primitive_mode); /// End a transform feedback - void EndTransformFeedback(); + void EndTransformFeedback(bool force = false); Tegra::GPU& gpu; @@ -254,6 +256,9 @@ private: bool has_written_global_memory = false; u32 last_clip_distance_mask = 0; + bool host_tfb_enabled{}; + bool prev_tfb_enabled{}; + GLuint transform_query{}; }; } // namespace OpenGL diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 51df18ec3a..8c4e854b21 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -610,4 +610,20 @@ void BufferCacheRuntime::ReserveNullBuffer() { }); } +vk::Buffer BufferCacheRuntime::CreateTransformCounterBuffer() { + return memory_allocator.CreateBuffer( + VkBufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = 4, + .usage = VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT | + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }, + MemoryUsage::DeviceLocal); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 95446c7327..f027ade8ed 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -83,7 +83,7 @@ public: void PreCopyBarrier(); - void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, + void CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer, std::span copies, bool barrier = true); void PostCopyBarrier(); @@ -124,6 +124,8 @@ public: guest_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format)); } + vk::Buffer CreateTransformCounterBuffer(); + private: void BindBuffer(VkBuffer buffer, u32 offset, u32 size) { guest_descriptor_queue.AddBuffer(buffer, offset, size); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 456bb040e8..21064dd266 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -176,6 +176,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), wfi_event(device.GetLogical().CreateEvent()) { scheduler.SetQueryCache(query_cache); + transform_counter = buffer_cache_runtime.CreateTransformCounterBuffer(); } RasterizerVulkan::~RasterizerVulkan() = default; @@ -206,13 +207,15 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); - BeginTransformFeedback(); + if (host_tfb_enabled && !maxwell3d->regs.transform_feedback_enabled) { + EndTransformFeedback(); + } else { + BeginTransformFeedback(); + } UpdateDynamicStates(); draw_func(); - - EndTransformFeedback(); } void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { @@ -902,30 +905,46 @@ void RasterizerVulkan::UpdateDynamicStates() { } void RasterizerVulkan::BeginTransformFeedback() { - const auto& regs = maxwell3d->regs; - if (regs.transform_feedback_enabled == 0) { - return; - } if (!device.IsExtTransformFeedbackSupported()) { LOG_ERROR(Render_Vulkan, "Transform feedbacks used but not supported"); return; } + const auto& regs = maxwell3d->regs; UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderType::TessellationInit) || regs.IsShaderConfigEnabled(Maxwell::ShaderType::Tessellation)); - scheduler.Record( - [](vk::CommandBuffer cmdbuf) { cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr); }); + + if (host_tfb_enabled) { + prev_tfb_enabled = regs.transform_feedback_enabled; + return; + } + + if (regs.transform_feedback_enabled && prev_tfb_enabled) { + // if current and previous tfbs are enabled, we're resuming. + scheduler.Record([buffer = *transform_counter](vk::CommandBuffer cmdbuf) { + cmdbuf.BeginTransformFeedbackEXT(0, 1, &buffer, nullptr); + }); + host_tfb_enabled = true; + } else if (regs.transform_feedback_enabled) { + scheduler.Record([](vk::CommandBuffer cmdbuf) { + cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr); + }); + host_tfb_enabled = true; + } + prev_tfb_enabled = regs.transform_feedback_enabled; } void RasterizerVulkan::EndTransformFeedback() { - const auto& regs = maxwell3d->regs; - if (regs.transform_feedback_enabled == 0) { - return; - } if (!device.IsExtTransformFeedbackSupported()) { return; } - scheduler.Record( - [](vk::CommandBuffer cmdbuf) { cmdbuf.EndTransformFeedbackEXT(0, 0, nullptr, nullptr); }); + + if (host_tfb_enabled) { + scheduler.Record([buffer = *transform_counter](vk::CommandBuffer cmdbuf) { + cmdbuf.EndTransformFeedbackEXT(0, 1, &buffer, nullptr); + }); + host_tfb_enabled = false; + } + prev_tfb_enabled = maxwell3d->regs.transform_feedback_enabled; } void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) { @@ -1494,4 +1513,22 @@ void RasterizerVulkan::ReleaseChannel(s32 channel_id) { query_cache.EraseChannel(channel_id); } +u32 RasterizerVulkan::GetTransformFeedbackByteCount() { + EndTransformFeedback(); + + auto download_staging = buffer_cache_runtime.DownloadStagingBuffer(4); + std::array copy{VideoCommon::BufferCopy{ + 0, + download_staging.offset, + 4, + }}; + buffer_cache_runtime.CopyBuffer(download_staging.buffer, *transform_counter, + std::span(copy)); + scheduler.Finish(); + + u32 count{}; + std::memcpy(&count, download_staging.mapped_span.data(), 4); + return count; +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 73257d964c..b646defb13 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -131,6 +131,8 @@ public: void ReleaseChannel(s32 channel_id) override; + u32 GetTransformFeedbackByteCount() override; + private: static constexpr size_t MAX_TEXTURES = 192; static constexpr size_t MAX_IMAGES = 48; @@ -206,6 +208,9 @@ private: boost::container::static_vector sampler_handles; u32 draw_counter = 0; + bool host_tfb_enabled{}; + bool prev_tfb_enabled{}; + vk::Buffer transform_counter; }; } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 2fa29793ae..675d26e5ed 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -100,6 +100,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { X(vkCmdDrawIndexedIndirect); X(vkCmdDrawIndirectCount); X(vkCmdDrawIndexedIndirectCount); + X(vkCmdDrawIndirectByteCountEXT); X(vkCmdEndQuery); X(vkCmdEndRenderPass); X(vkCmdEndTransformFeedbackEXT); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 32bd75ad81..b06e369cf6 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -224,6 +224,7 @@ struct DeviceDispatch : InstanceDispatch { PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect{}; PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount{}; PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount{}; + PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT{}; PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{}; PFN_vkCmdEndQuery vkCmdEndQuery{}; PFN_vkCmdEndRenderPass vkCmdEndRenderPass{}; @@ -1196,6 +1197,13 @@ public: count_offset, draw_count, stride); } + void DrawIndirectByteCountEXT(u32 instance_count, u32 first_instance, VkBuffer counter_buffer, + VkDeviceSize counter_buffer_offset, u32 counter_offset, + u32 vertex_stride) const noexcept { + dld->vkCmdDrawIndirectByteCountEXT(handle, instance_count, first_instance, counter_buffer, + counter_buffer_offset, counter_offset, vertex_stride); + } + void ClearAttachments(Span attachments, Span rects) const noexcept { dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 195d3556c9..1c075fc211 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -764,6 +764,7 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); ReadGlobalSetting(Settings::values.nvdec_emulation); ReadGlobalSetting(Settings::values.accelerate_astc); + ReadGlobalSetting(Settings::values.transform_feedback_query); ReadGlobalSetting(Settings::values.async_astc); ReadGlobalSetting(Settings::values.astc_recompression); ReadGlobalSetting(Settings::values.use_reactive_flushing); @@ -1429,6 +1430,7 @@ void Config::SaveRendererValues() { static_cast(Settings::values.nvdec_emulation.GetDefault()), Settings::values.nvdec_emulation.UsingGlobal()); WriteGlobalSetting(Settings::values.accelerate_astc); + WriteGlobalSetting(Settings::values.transform_feedback_query); WriteGlobalSetting(Settings::values.async_astc); WriteSetting(QString::fromStdString(Settings::values.astc_recompression.GetLabel()), static_cast(Settings::values.astc_recompression.GetValue(global)), diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index c0a044767a..5e20b0ec80 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -45,6 +45,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { ui->use_video_framerate_checkbox->setChecked(Settings::values.use_video_framerate.GetValue()); ui->barrier_feedback_loops_checkbox->setChecked( Settings::values.barrier_feedback_loops.GetValue()); + ui->transform_feedback_query->setChecked(Settings::values.transform_feedback_query.GetValue()); if (Settings::IsConfiguringGlobal()) { ui->gpu_accuracy->setCurrentIndex( @@ -99,6 +100,9 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting(&Settings::values.barrier_feedback_loops, ui->barrier_feedback_loops_checkbox, barrier_feedback_loops); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.transform_feedback_query, + ui->transform_feedback_query, + transform_feedback_query); } void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { @@ -137,6 +141,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { Settings::values.use_video_framerate.UsingGlobal()); ui->barrier_feedback_loops_checkbox->setEnabled( Settings::values.barrier_feedback_loops.UsingGlobal()); + ui->transform_feedback_query->setEnabled( + Settings::values.transform_feedback_query.UsingGlobal()); return; } @@ -167,6 +173,10 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { ConfigurationShared::SetColoredTristate(ui->barrier_feedback_loops_checkbox, Settings::values.barrier_feedback_loops, barrier_feedback_loops); + ConfigurationShared::SetColoredTristate(ui->transform_feedback_query, + Settings::values.transform_feedback_query, + transform_feedback_query); + ConfigurationShared::SetColoredComboBox( ui->gpu_accuracy, ui->label_gpu_accuracy, static_cast(Settings::values.gpu_accuracy.GetValue(true))); diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index 369a7c83e2..9ec46b32dc 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -49,6 +49,7 @@ private: ConfigurationShared::CheckState enable_compute_pipelines; ConfigurationShared::CheckState use_video_framerate; ConfigurationShared::CheckState barrier_feedback_loops; + ConfigurationShared::CheckState transform_feedback_query; const Core::System& system; }; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index d527a6f38b..f8f79d1381 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -72,44 +72,44 @@ - - 0 - - - 0 - - - 0 - - - 0 - - - + + 0 + + + 0 + + + 0 + + + 0 + + + + + ASTC recompression: + + + + + + - ASTC recompression: + Uncompressed (Best quality) - - - - - - - Uncompressed (Best quality) - - - - - BC1 (Low quality) - - - - - BC3 (Medium quality) - - - - + + + + BC1 (Low quality) + + + + + BC3 (Medium quality) + + + + @@ -211,6 +211,16 @@ Compute pipelines are always enabled on all other drivers. + + + + Enable Transform Feedback queries + + + Enables querying the TFB counter for TFB draws. Can noticeably reduce performance of some games if they query TFB but not rely on it to draw. + + +