diff options
-rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 8 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.h | 4 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.cpp | 17 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.h | 5 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_scheduler.cpp | 21 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_scheduler.h | 42 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_state_tracker.cpp | 97 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_state_tracker.h | 53 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 1 |
10 files changed, 198 insertions, 52 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 18b774ac7..06c174a5b 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -199,6 +199,8 @@ if (ENABLE_VULKAN) renderer_vulkan/vk_shader_util.h renderer_vulkan/vk_staging_buffer_pool.cpp renderer_vulkan/vk_staging_buffer_pool.h + renderer_vulkan/vk_state_tracker.cpp + renderer_vulkan/vk_state_tracker.h renderer_vulkan/vk_stream_buffer.cpp renderer_vulkan/vk_stream_buffer.h renderer_vulkan/vk_swapchain.cpp diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index ddc62bc97..42bb01418 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -27,6 +27,7 @@ #include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_resource_manager.h" #include "video_core/renderer_vulkan/vk_scheduler.h" +#include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_swapchain.h" namespace Vulkan { @@ -177,10 +178,13 @@ bool RendererVulkan::Init() { swapchain = std::make_unique<VKSwapchain>(surface, *device); swapchain->Create(framebuffer.width, framebuffer.height, false); - scheduler = std::make_unique<VKScheduler>(*device, *resource_manager); + state_tracker = std::make_unique<StateTracker>(system); + + scheduler = std::make_unique<VKScheduler>(*device, *resource_manager, *state_tracker); rasterizer = std::make_unique<RasterizerVulkan>(system, render_window, screen_info, *device, - *resource_manager, *memory_manager, *scheduler); + *resource_manager, *memory_manager, + *state_tracker, *scheduler); blit_screen = std::make_unique<VKBlitScreen>(system, render_window, *rasterizer, *device, *resource_manager, *memory_manager, *swapchain, diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index f513397f0..3da08d2e4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -4,8 +4,10 @@ #pragma once +#include <memory> #include <optional> #include <vector> + #include "video_core/renderer_base.h" #include "video_core/renderer_vulkan/declarations.h" @@ -15,6 +17,7 @@ class System; namespace Vulkan { +class StateTracker; class VKBlitScreen; class VKDevice; class VKFence; @@ -61,6 +64,7 @@ private: std::unique_ptr<VKSwapchain> swapchain; std::unique_ptr<VKMemoryManager> memory_manager; std::unique_ptr<VKResourceManager> resource_manager; + std::unique_ptr<StateTracker> state_tracker; std::unique_ptr<VKScheduler> scheduler; std::unique_ptr<VKBlitScreen> blit_screen; }; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index b1be41a21..41cbf4134 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -36,6 +36,7 @@ #include "video_core/renderer_vulkan/vk_sampler_cache.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" +#include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" @@ -277,10 +278,11 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf, RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& renderer, VKScreenInfo& screen_info, const VKDevice& device, VKResourceManager& resource_manager, - VKMemoryManager& memory_manager, VKScheduler& scheduler) + VKMemoryManager& memory_manager, StateTracker& state_tracker, + VKScheduler& scheduler) : RasterizerAccelerated{system.Memory()}, system{system}, render_window{renderer}, screen_info{screen_info}, device{device}, resource_manager{resource_manager}, - memory_manager{memory_manager}, scheduler{scheduler}, + memory_manager{memory_manager}, state_tracker{state_tracker}, scheduler{scheduler}, staging_pool(device, memory_manager, scheduler), descriptor_pool(device), update_descriptor_queue(device, scheduler), quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), @@ -545,6 +547,10 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, return true; } +void RasterizerVulkan::SetupDirtyFlags() { + state_tracker.Initialize(); +} + void RasterizerVulkan::FlushWork() { static constexpr u32 DRAWS_TO_DISPATCH = 4096; @@ -568,7 +574,9 @@ void RasterizerVulkan::FlushWork() { RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() { MICROPROFILE_SCOPE(Vulkan_RenderTargets); - constexpr bool update_rendertargets = true; + auto& dirty = system.GPU().Maxwell3D().dirty.flags; + const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets]; + dirty[VideoCommon::Dirty::RenderTargets] = false; texture_cache.GuardRenderTargets(true); @@ -971,6 +979,9 @@ void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const Ima } void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D& gpu) { + if (!state_tracker.TouchViewports()) { + return; + } const auto& regs = gpu.regs; const std::array viewports{ GetViewportState(device, regs, 0), GetViewportState(device, regs, 1), diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 4dc8af6e8..a79440eba 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -96,6 +96,7 @@ struct hash<Vulkan::FramebufferCacheKey> { namespace Vulkan { +class StateTracker; class BufferBindings; struct ImageView { @@ -108,7 +109,7 @@ public: explicit RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& render_window, VKScreenInfo& screen_info, const VKDevice& device, VKResourceManager& resource_manager, VKMemoryManager& memory_manager, - VKScheduler& scheduler); + StateTracker& state_tracker, VKScheduler& scheduler); ~RasterizerVulkan() override; void Draw(bool is_indexed, bool is_instanced) override; @@ -127,6 +128,7 @@ public: const Tegra::Engines::Fermi2D::Config& copy_config) override; bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride) override; + void SetupDirtyFlags() override; /// Maximum supported size that a constbuffer can have in bytes. static constexpr std::size_t MaxConstbufferSize = 0x10000; @@ -241,6 +243,7 @@ private: const VKDevice& device; VKResourceManager& resource_manager; VKMemoryManager& memory_manager; + StateTracker& state_tracker; VKScheduler& scheduler; VKStagingBufferPool staging_pool; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 92bd6c344..b61d4fe63 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -2,6 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <memory> +#include <mutex> +#include <optional> +#include <thread> +#include <utility> + #include "common/assert.h" #include "common/microprofile.h" #include "video_core/renderer_vulkan/declarations.h" @@ -9,6 +15,7 @@ #include "video_core/renderer_vulkan/vk_query_cache.h" #include "video_core/renderer_vulkan/vk_resource_manager.h" #include "video_core/renderer_vulkan/vk_scheduler.h" +#include "video_core/renderer_vulkan/vk_state_tracker.h" namespace Vulkan { @@ -29,9 +36,10 @@ void VKScheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf, last = nullptr; } -VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_manager) - : device{device}, resource_manager{resource_manager}, next_fence{ - &resource_manager.CommitFence()} { +VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_manager, + StateTracker& state_tracker) + : device{device}, resource_manager{resource_manager}, state_tracker{state_tracker}, + next_fence{&resource_manager.CommitFence()} { AcquireNewChunk(); AllocateNewContext(); worker_thread = std::thread(&VKScheduler::WorkerThread, this); @@ -157,12 +165,7 @@ void VKScheduler::AllocateNewContext() { void VKScheduler::InvalidateState() { state.graphics_pipeline = nullptr; - state.viewports = false; - state.scissors = false; - state.depth_bias = false; - state.blend_constants = false; - state.depth_bounds = false; - state.stencil_values = false; + state_tracker.InvalidateCommandBufferState(); } void VKScheduler::EndPendingOperations() { diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 62fd7858b..c7cc291c3 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -17,6 +17,7 @@ namespace Vulkan { +class StateTracker; class VKDevice; class VKFence; class VKQueryCache; @@ -43,7 +44,8 @@ private: /// OpenGL-like operations on Vulkan command buffers. class VKScheduler { public: - explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager); + explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager, + StateTracker& state_tracker); ~VKScheduler(); /// Sends the current execution context to the GPU. @@ -74,36 +76,6 @@ public: query_cache = &query_cache_; } - /// Returns true when viewports have been set in the current command buffer. - bool TouchViewports() { - return std::exchange(state.viewports, true); - } - - /// Returns true when scissors have been set in the current command buffer. - bool TouchScissors() { - return std::exchange(state.scissors, true); - } - - /// Returns true when depth bias have been set in the current command buffer. - bool TouchDepthBias() { - return std::exchange(state.depth_bias, true); - } - - /// Returns true when blend constants have been set in the current command buffer. - bool TouchBlendConstants() { - return std::exchange(state.blend_constants, true); - } - - /// Returns true when depth bounds have been set in the current command buffer. - bool TouchDepthBounds() { - return std::exchange(state.depth_bounds, true); - } - - /// Returns true when stencil values have been set in the current command buffer. - bool TouchStencilValues() { - return std::exchange(state.stencil_values, true); - } - /// Send work to a separate thread. template <typename T> void Record(T&& command) { @@ -217,6 +189,8 @@ private: const VKDevice& device; VKResourceManager& resource_manager; + StateTracker& state_tracker; + VKQueryCache* query_cache = nullptr; vk::CommandBuffer current_cmdbuf; @@ -226,12 +200,6 @@ private: struct State { std::optional<vk::RenderPassBeginInfo> renderpass; vk::Pipeline graphics_pipeline; - bool viewports = false; - bool scissors = false; - bool depth_bias = false; - bool blend_constants = false; - bool depth_bounds = false; - bool stencil_values = false; } state; std::unique_ptr<CommandChunk> chunk; diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp new file mode 100644 index 000000000..d44992dc9 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp @@ -0,0 +1,97 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <type_traits> + +#include "common/common_types.h" +#include "core/core.h" +#include "video_core/engines/maxwell_3d.h" +#include "video_core/gpu.h" +#include "video_core/renderer_vulkan/vk_state_tracker.h" + +#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name) +#define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / sizeof(u32)) + +namespace Vulkan { + +namespace { + +using namespace Dirty; +using namespace VideoCommon::Dirty; +using Tegra::Engines::Maxwell3D; +using Regs = Maxwell3D::Regs; +using Dirty = std::remove_reference_t<decltype(Maxwell3D::dirty)>; +using Tables = std::remove_reference_t<decltype(Maxwell3D::dirty.tables)>; +using Table = std::remove_reference_t<decltype(Maxwell3D::dirty.tables[0])>; +using Flags = std::remove_reference_t<decltype(Maxwell3D::dirty.flags)>; + +Flags MakeInvalidationFlags() { + Flags flags{}; + flags[Viewports] = true; + return flags; +} + +template <typename Integer> +void FillBlock(Table& table, std::size_t begin, std::size_t num, Integer dirty_index) { + const auto it = std::begin(table) + begin; + std::fill(it, it + num, static_cast<u8>(dirty_index)); +} + +template <typename Integer1, typename Integer2> +void FillBlock(Tables& tables, std::size_t begin, std::size_t num, Integer1 index_a, + Integer2 index_b) { + FillBlock(tables[0], begin, num, index_a); + FillBlock(tables[1], begin, num, index_b); +} + +void SetupDirtyRenderTargets(Tables& tables) { + static constexpr std::size_t num_per_rt = NUM(rt[0]); + static constexpr std::size_t begin = OFF(rt); + static constexpr std::size_t num = num_per_rt * Regs::NumRenderTargets; + for (std::size_t rt = 0; rt < Regs::NumRenderTargets; ++rt) { + FillBlock(tables[0], begin + rt * num_per_rt, num_per_rt, ColorBuffer0 + rt); + } + FillBlock(tables[1], begin, num, RenderTargets); + + static constexpr std::array zeta_flags{ZetaBuffer, RenderTargets}; + for (std::size_t i = 0; i < std::size(zeta_flags); ++i) { + const u8 flag = zeta_flags[i]; + auto& table = tables[i]; + table[OFF(zeta_enable)] = flag; + table[OFF(zeta_width)] = flag; + table[OFF(zeta_height)] = flag; + FillBlock(table, OFF(zeta), NUM(zeta), flag); + } +} + +void SetupDirtyViewports(Tables& tables) { + FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports); + FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports); + tables[0][OFF(viewport_transform_enabled)] = Viewports; +} + +} // Anonymous namespace + +StateTracker::StateTracker(Core::System& system) + : system{system}, invalidation_flags{MakeInvalidationFlags()} {} + +void StateTracker::Initialize() { + auto& dirty = system.GPU().Maxwell3D().dirty; + auto& tables = dirty.tables; + SetupDirtyRenderTargets(tables); + SetupDirtyViewports(tables); + + auto& store = dirty.on_write_stores; + store[RenderTargets] = true; + store[ZetaBuffer] = true; + for (std::size_t i = 0; i < Regs::NumRenderTargets; ++i) { + store[ColorBuffer0 + i] = true; + } +} + +void StateTracker::InvalidateCommandBufferState() { + system.GPU().Maxwell3D().dirty.flags |= invalidation_flags; +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h new file mode 100644 index 000000000..9ec7b5136 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h @@ -0,0 +1,53 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <type_traits> // REMOVE ME +#include <utility> + +#include "common/common_types.h" +#include "core/core.h" +#include "video_core/dirty_flags.h" +#include "video_core/engines/maxwell_3d.h" + +namespace Vulkan { + +namespace Dirty { + +enum : u8 { + First = VideoCommon::Dirty::LastCommonEntry, + + Viewports, +}; + +} // namespace Dirty + +class StateTracker { +public: + explicit StateTracker(Core::System& system); + + void Initialize(); + + void InvalidateCommandBufferState(); + + bool TouchViewports() { + return Exchange(Dirty::Viewports, false); + } + +private: + using Flags = std::remove_reference_t<decltype(Tegra::Engines::Maxwell3D::dirty.flags)>; + + bool Exchange(std::size_t id, bool new_value) const noexcept { + auto& flags = system.GPU().Maxwell3D().dirty.flags; + const bool is_dirty = flags[id]; + flags[id] = new_value; + return is_dirty; + } + + Core::System& system; + Flags invalidation_flags; +}; + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 51b0d38a6..73d92a5ae 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -22,6 +22,7 @@ #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" +#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/surface.h" |