summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/StateTracker.h
blob: da0e4d8387d9c8afa6c103c05be3ed7898f5fffa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright 2016 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <cstddef>
#include <memory>

#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 command 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<VkDescriptorBufferInfo, NUM_UBO_DESCRIPTOR_SET_BINDINGS> gx_ubo_bindings;
    std::array<u32, NUM_UBO_DESCRIPTOR_SET_BINDINGS> gx_ubo_offsets;
    VkDescriptorBufferInfo utility_ubo_binding;
    u32 utility_ubo_offset;
    std::array<VkDescriptorImageInfo, VideoCommon::MAX_PIXEL_SHADER_SAMPLERS> samplers;
    std::array<VkBufferView, NUM_COMPUTE_TEXEL_BUFFERS> texel_buffers;
    VkDescriptorBufferInfo ssbo;
    VkDescriptorBufferInfo gx_uber_vertex_ssbo;
    std::array<VkDescriptorImageInfo, VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS> image_textures;
  } m_bindings = {};
  std::array<VkDescriptorSet, NUM_GX_DESCRIPTOR_SETS> m_gx_descriptor_sets = {};
  std::array<VkDescriptorSet, NUM_UTILITY_DESCRIPTOR_SETS> 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<VKTexture> m_dummy_texture;
  std::unique_ptr<VKTexture> m_dummy_compute_texture;

  VKFramebuffer* m_framebuffer = nullptr;
  VkRenderPass m_current_render_pass = VK_NULL_HANDLE;
  VkRect2D m_framebuffer_render_area = {};
};
}  // namespace Vulkan