1 // Copyright 2016 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <array>
8 #include <cstddef>
9 #include <memory>
10 
11 #include "Common/CommonTypes.h"
12 #include "VideoBackends/Vulkan/Constants.h"
13 #include "VideoCommon/RenderBase.h"
14 
15 namespace Vulkan
16 {
17 class VKFramebuffer;
18 class VKShader;
19 class VKPipeline;
20 class VKTexture;
21 class StreamBuffer;
22 class VertexFormat;
23 
24 class StateTracker
25 {
26 public:
27   StateTracker();
28   ~StateTracker();
29 
30   static StateTracker* GetInstance();
31   static bool CreateInstance();
32   static void DestroyInstance();
33 
GetFramebuffer()34   VKFramebuffer* GetFramebuffer() const { return m_framebuffer; }
GetPipeline()35   const VKPipeline* GetPipeline() const { return m_pipeline; }
36   void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
37   void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
38   void SetFramebuffer(VKFramebuffer* framebuffer);
39   void SetPipeline(const VKPipeline* pipeline);
40   void SetComputeShader(const VKShader* shader);
41   void SetGXUniformBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size);
42   void SetUtilityUniformBuffer(VkBuffer buffer, u32 offset, u32 size);
43   void SetTexture(u32 index, VkImageView view);
44   void SetSampler(u32 index, VkSampler sampler);
45   void SetSSBO(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range);
46   void SetTexelBuffer(u32 index, VkBufferView view);
47   void SetImageTexture(VkImageView view);
48 
49   void UnbindTexture(VkImageView view);
50 
51   // Set dirty flags on everything to force re-bind at next draw time.
52   void InvalidateCachedState();
53 
54   // Ends a render pass if we're currently in one.
55   // When Bind() is next called, the pass will be restarted.
56   // Calling this function is allowed even if a pass has not begun.
InRenderPass()57   bool InRenderPass() const { return m_current_render_pass != VK_NULL_HANDLE; }
58   void BeginRenderPass();
59   void BeginDiscardRenderPass();
60   void EndRenderPass();
61 
62   // Ends the current render pass if it was a clear render pass.
63   void BeginClearRenderPass(const VkRect2D& area, const VkClearValue* clear_values,
64                             u32 num_clear_values);
65   void EndClearRenderPass();
66 
67   void SetViewport(const VkViewport& viewport);
68   void SetScissor(const VkRect2D& scissor);
69 
70   // Binds all dirty state to the commmand buffer.
71   // If this returns false, you should not issue the draw.
72   bool Bind();
73 
74   // Binds all dirty compute state to the command buffer.
75   // If this returns false, you should not dispatch the shader.
76   bool BindCompute();
77 
78   // Returns true if the specified rectangle is inside the current render area (used for clears).
79   bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const;
80 
81 private:
82   // Number of descriptor sets for game draws.
83   enum
84   {
85     NUM_GX_DESCRIPTOR_SETS = 3,
86     NUM_UTILITY_DESCRIPTOR_SETS = 2,
87     NUM_COMPUTE_DESCRIPTOR_SETS = 1
88   };
89 
90   enum DIRTY_FLAG : u32
91   {
92     DIRTY_FLAG_GX_UBOS = (1 << 0),
93     DIRTY_FLAG_GX_UBO_OFFSETS = (1 << 1),
94     DIRTY_FLAG_GX_SAMPLERS = (1 << 4),
95     DIRTY_FLAG_GX_SSBO = (1 << 5),
96     DIRTY_FLAG_UTILITY_UBO = (1 << 2),
97     DIRTY_FLAG_UTILITY_UBO_OFFSET = (1 << 3),
98     DIRTY_FLAG_UTILITY_BINDINGS = (1 << 6),
99     DIRTY_FLAG_COMPUTE_BINDINGS = (1 << 7),
100     DIRTY_FLAG_VERTEX_BUFFER = (1 << 8),
101     DIRTY_FLAG_INDEX_BUFFER = (1 << 9),
102     DIRTY_FLAG_VIEWPORT = (1 << 10),
103     DIRTY_FLAG_SCISSOR = (1 << 11),
104     DIRTY_FLAG_PIPELINE = (1 << 12),
105     DIRTY_FLAG_COMPUTE_SHADER = (1 << 13),
106     DIRTY_FLAG_DESCRIPTOR_SETS = (1 << 14),
107     DIRTY_FLAG_COMPUTE_DESCRIPTOR_SET = (1 << 15),
108 
109     DIRTY_FLAG_ALL_DESCRIPTORS = DIRTY_FLAG_GX_UBOS | DIRTY_FLAG_UTILITY_UBO |
110                                  DIRTY_FLAG_GX_SAMPLERS | DIRTY_FLAG_GX_SSBO |
111                                  DIRTY_FLAG_UTILITY_BINDINGS | DIRTY_FLAG_COMPUTE_BINDINGS
112   };
113 
114   bool Initialize();
115 
116   // Check that the specified viewport is within the render area.
117   // If not, ends the render pass if it is a clear render pass.
118   bool IsViewportWithinRenderArea() const;
119 
120   bool UpdateDescriptorSet();
121   bool UpdateGXDescriptorSet();
122   bool UpdateUtilityDescriptorSet();
123   bool UpdateComputeDescriptorSet();
124 
125   // Which bindings/state has to be updated before the next draw.
126   u32 m_dirty_flags = 0;
127 
128   // input assembly
129   VkBuffer m_vertex_buffer = VK_NULL_HANDLE;
130   VkDeviceSize m_vertex_buffer_offset = 0;
131   VkBuffer m_index_buffer = VK_NULL_HANDLE;
132   VkDeviceSize m_index_buffer_offset = 0;
133   VkIndexType m_index_type = VK_INDEX_TYPE_UINT16;
134 
135   // pipeline state
136   const VKPipeline* m_pipeline = nullptr;
137   const VKShader* m_compute_shader = nullptr;
138 
139   // shader bindings
140   struct
141   {
142     std::array<VkDescriptorBufferInfo, NUM_UBO_DESCRIPTOR_SET_BINDINGS> gx_ubo_bindings;
143     std::array<u32, NUM_UBO_DESCRIPTOR_SET_BINDINGS> gx_ubo_offsets;
144     VkDescriptorBufferInfo utility_ubo_binding;
145     u32 utility_ubo_offset;
146     std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS> samplers;
147     std::array<VkBufferView, NUM_COMPUTE_TEXEL_BUFFERS> texel_buffers;
148     VkDescriptorBufferInfo ssbo;
149     VkDescriptorImageInfo image_texture;
150   } m_bindings = {};
151   std::array<VkDescriptorSet, NUM_GX_DESCRIPTOR_SETS> m_gx_descriptor_sets = {};
152   std::array<VkDescriptorSet, NUM_UTILITY_DESCRIPTOR_SETS> m_utility_descriptor_sets = {};
153   VkDescriptorSet m_compute_descriptor_set = VK_NULL_HANDLE;
154 
155   // rasterization
156   VkViewport m_viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
157   VkRect2D m_scissor = {{0, 0}, {1, 1}};
158 
159   // uniform buffers
160   std::unique_ptr<VKTexture> m_dummy_texture;
161 
162   VKFramebuffer* m_framebuffer = nullptr;
163   VkRenderPass m_current_render_pass = VK_NULL_HANDLE;
164   VkRect2D m_framebuffer_render_area = {};
165 };
166 }  // namespace Vulkan
167