// Copyright 2016 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include "Common/CommonTypes.h" #include "VideoBackends/Vulkan/Constants.h" #include "VideoCommon/Constants.h" namespace Vulkan { class VKFramebuffer; class VKShader; class VKPipeline; class VKTexture; class StreamBuffer; class VertexFormat; class StateTracker { public: StateTracker(); ~StateTracker(); static StateTracker* GetInstance(); static bool CreateInstance(); static void DestroyInstance(); VKFramebuffer* GetFramebuffer() const { return m_framebuffer; } const VKPipeline* GetPipeline() const { return m_pipeline; } void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset, u32 size); void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type); void SetFramebuffer(VKFramebuffer* framebuffer); void SetPipeline(const VKPipeline* pipeline); void SetComputeShader(const VKShader* shader); void SetGXUniformBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size); void SetUtilityUniformBuffer(VkBuffer buffer, u32 offset, u32 size); void SetTexture(u32 index, VkImageView view); void SetSampler(u32 index, VkSampler sampler); void SetSSBO(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range); void SetTexelBuffer(u32 index, VkBufferView view); void SetImageTexture(u32 index, VkImageView view); void UnbindTexture(VkImageView view); // Set dirty flags on everything to force re-bind at next draw time. void InvalidateCachedState(); // Ends a render pass if we're currently in one. // When Bind() is next called, the pass will be restarted. // Calling this function is allowed even if a pass has not begun. bool InRenderPass() const { return m_current_render_pass != VK_NULL_HANDLE; } void BeginRenderPass(); void BeginDiscardRenderPass(); void EndRenderPass(); // Ends the current render pass if it was a clear render pass. void BeginClearRenderPass(const VkRect2D& area, const VkClearValue* clear_values, u32 num_clear_values); void EndClearRenderPass(); void SetViewport(const VkViewport& viewport); void SetScissor(const VkRect2D& scissor); // Binds all dirty state to the commmand buffer. // If this returns false, you should not issue the draw. bool Bind(); // Binds all dirty compute state to the command buffer. // If this returns false, you should not dispatch the shader. bool BindCompute(); // Returns true if the specified rectangle is inside the current render area (used for clears). bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const; private: // Number of descriptor sets for game draws. enum { NUM_GX_DESCRIPTOR_SETS = 3, NUM_UTILITY_DESCRIPTOR_SETS = 2, NUM_COMPUTE_DESCRIPTOR_SETS = 1 }; enum DIRTY_FLAG : u32 { DIRTY_FLAG_GX_UBOS = (1 << 0), DIRTY_FLAG_GX_UBO_OFFSETS = (1 << 1), DIRTY_FLAG_GX_SAMPLERS = (1 << 4), DIRTY_FLAG_GX_SSBO = (1 << 5), DIRTY_FLAG_UTILITY_UBO = (1 << 2), DIRTY_FLAG_UTILITY_UBO_OFFSET = (1 << 3), DIRTY_FLAG_UTILITY_BINDINGS = (1 << 6), DIRTY_FLAG_COMPUTE_BINDINGS = (1 << 7), DIRTY_FLAG_VERTEX_BUFFER = (1 << 8), DIRTY_FLAG_INDEX_BUFFER = (1 << 9), DIRTY_FLAG_VIEWPORT = (1 << 10), DIRTY_FLAG_SCISSOR = (1 << 11), DIRTY_FLAG_PIPELINE = (1 << 12), DIRTY_FLAG_COMPUTE_SHADER = (1 << 13), DIRTY_FLAG_DESCRIPTOR_SETS = (1 << 14), DIRTY_FLAG_COMPUTE_DESCRIPTOR_SET = (1 << 15), DIRTY_FLAG_ALL_DESCRIPTORS = DIRTY_FLAG_GX_UBOS | DIRTY_FLAG_UTILITY_UBO | DIRTY_FLAG_GX_SAMPLERS | DIRTY_FLAG_GX_SSBO | DIRTY_FLAG_UTILITY_BINDINGS | DIRTY_FLAG_COMPUTE_BINDINGS }; bool Initialize(); // Check that the specified viewport is within the render area. // If not, ends the render pass if it is a clear render pass. bool IsViewportWithinRenderArea() const; void UpdateDescriptorSet(); void UpdateGXDescriptorSet(); void UpdateUtilityDescriptorSet(); void UpdateComputeDescriptorSet(); // Which bindings/state has to be updated before the next draw. u32 m_dirty_flags = 0; // input assembly VkBuffer m_vertex_buffer = VK_NULL_HANDLE; VkDeviceSize m_vertex_buffer_offset = 0; VkBuffer m_index_buffer = VK_NULL_HANDLE; VkDeviceSize m_index_buffer_offset = 0; VkIndexType m_index_type = VK_INDEX_TYPE_UINT16; // pipeline state const VKPipeline* m_pipeline = nullptr; const VKShader* m_compute_shader = nullptr; // shader bindings struct { std::array gx_ubo_bindings; std::array gx_ubo_offsets; VkDescriptorBufferInfo utility_ubo_binding; u32 utility_ubo_offset; std::array samplers; std::array texel_buffers; VkDescriptorBufferInfo ssbo; VkDescriptorBufferInfo gx_uber_vertex_ssbo; std::array image_textures; } m_bindings = {}; std::array m_gx_descriptor_sets = {}; std::array m_utility_descriptor_sets = {}; VkDescriptorSet m_compute_descriptor_set = VK_NULL_HANDLE; // rasterization VkViewport m_viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; VkRect2D m_scissor = {{0, 0}, {1, 1}}; // uniform buffers std::unique_ptr m_dummy_texture; std::unique_ptr m_dummy_compute_texture; VKFramebuffer* m_framebuffer = nullptr; VkRenderPass m_current_render_pass = VK_NULL_HANDLE; VkRect2D m_framebuffer_render_area = {}; }; } // namespace Vulkan