| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | // Copyright 2016 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2+
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-30 23:07:50 -04:00
										 |  |  | #include <array>
 | 
					
						
							|  |  |  | #include <cstddef>
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include <memory>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-30 23:07:50 -04:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  | #include "Common/LinearDiskCache.h"
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include "VideoBackends/Vulkan/Constants.h"
 | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:33 +10:00
										 |  |  | #include "VideoBackends/Vulkan/ShaderCache.h"
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include "VideoCommon/GeometryShaderGen.h"
 | 
					
						
							| 
									
										
										
										
											2017-01-31 23:29:29 -05:00
										 |  |  | #include "VideoCommon/NativeVertexFormat.h"
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include "VideoCommon/PixelShaderGen.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/RenderBase.h"
 | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:35 +10:00
										 |  |  | #include "VideoCommon/UberShaderPixel.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/UberShaderVertex.h"
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include "VideoCommon/VertexShaderGen.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Vulkan | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | class StreamBuffer; | 
					
						
							|  |  |  | class VertexFormat; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class StateTracker | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-10-22 20:50:36 +10:00
										 |  |  |   StateTracker() = default; | 
					
						
							|  |  |  |   ~StateTracker() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static StateTracker* GetInstance(); | 
					
						
							|  |  |  |   static bool CreateInstance(); | 
					
						
							|  |  |  |   static void DestroyInstance(); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const RasterizationState& GetRasterizationState() const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return m_pipeline_state.rasterization_state; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-04-30 15:54:45 +10:00
										 |  |  |   const DepthState& GetDepthStencilState() const { return m_pipeline_state.depth_state; } | 
					
						
							| 
									
										
										
										
											2017-04-17 23:14:17 +10:00
										 |  |  |   const BlendingState& GetBlendState() const { return m_pipeline_state.blend_state; } | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset); | 
					
						
							|  |  |  |   void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-11 16:37:41 +10:00
										 |  |  |   void SetRenderPass(VkRenderPass load_render_pass, VkRenderPass clear_render_pass); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   void SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area); | 
					
						
							|  |  |  |   void SetVertexFormat(const VertexFormat* vertex_format); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void SetRasterizationState(const RasterizationState& state); | 
					
						
							| 
									
										
										
										
											2017-04-30 18:07:57 +10:00
										 |  |  |   void SetMultisamplingstate(const MultisamplingState& state); | 
					
						
							| 
									
										
										
										
											2017-04-30 15:54:45 +10:00
										 |  |  |   void SetDepthState(const DepthState& state); | 
					
						
							| 
									
										
										
										
											2017-04-17 23:14:17 +10:00
										 |  |  |   void SetBlendState(const BlendingState& state); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 18:07:57 +10:00
										 |  |  |   bool CheckForShaderChanges(); | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:35 +10:00
										 |  |  |   void ClearShaders(); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void UpdateVertexShaderConstants(); | 
					
						
							|  |  |  |   void UpdateGeometryShaderConstants(); | 
					
						
							|  |  |  |   void UpdatePixelShaderConstants(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void SetTexture(size_t index, VkImageView view); | 
					
						
							|  |  |  |   void SetSampler(size_t index, VkSampler sampler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void SetBBoxEnable(bool enable); | 
					
						
							|  |  |  |   void SetBBoxBuffer(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void UnbindTexture(VkImageView view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // When executing a command buffer, we want to recreate the descriptor set, as it will
 | 
					
						
							|  |  |  |   // now be in a different pool for the new command buffer.
 | 
					
						
							|  |  |  |   void InvalidateDescriptorSets(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-30 22:31:41 +10:00
										 |  |  |   // Same with the uniforms, as the current storage will belong to the previous command buffer.
 | 
					
						
							|  |  |  |   void InvalidateConstants(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   // Set dirty flags on everything to force re-bind at next draw time.
 | 
					
						
							|  |  |  |   void SetPendingRebind(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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 EndRenderPass(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-11 16:37:41 +10:00
										 |  |  |   // Ends the current render pass if it was a clear render pass.
 | 
					
						
							|  |  |  |   void BeginClearRenderPass(const VkRect2D& area, const VkClearValue clear_values[2]); | 
					
						
							|  |  |  |   void EndClearRenderPass(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   void SetViewport(const VkViewport& viewport); | 
					
						
							|  |  |  |   void SetScissor(const VkRect2D& scissor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool Bind(bool rebind_all = false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // CPU Access Tracking
 | 
					
						
							|  |  |  |   // Call after a draw call is made.
 | 
					
						
							|  |  |  |   void OnDraw(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Call after CPU access is requested.
 | 
					
						
							|  |  |  |   // This can be via EFBCache or EFB2RAM.
 | 
					
						
							|  |  |  |   void OnReadback(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Call at the end of a frame.
 | 
					
						
							|  |  |  |   void OnEndFrame(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Prevent/allow background command buffer execution.
 | 
					
						
							|  |  |  |   // Use when queries are active.
 | 
					
						
							|  |  |  |   void SetBackgroundCommandBufferExecution(bool enabled); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-11 16:37:41 +10:00
										 |  |  |   bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  |   // Reloads the UID cache, ensuring all pipelines used by the game so far have been created.
 | 
					
						
							| 
									
										
										
										
											2017-06-24 19:58:14 +10:00
										 |  |  |   void ReloadPipelineUIDCache(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Clears shader pointers, ensuring that now-deleted modules are not used.
 | 
					
						
							|  |  |  |   void InvalidateShaderPointers(); | 
					
						
							| 
									
										
										
										
											2016-10-22 20:50:36 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  | private: | 
					
						
							|  |  |  |   // Serialized version of PipelineInfo, used when loading/saving the pipeline UID cache.
 | 
					
						
							|  |  |  |   struct SerializedPipelineUID | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     u32 rasterizer_state_bits; | 
					
						
							| 
									
										
										
										
											2017-04-30 15:54:45 +10:00
										 |  |  |     u32 depth_state_bits; | 
					
						
							| 
									
										
										
										
											2017-04-17 23:14:17 +10:00
										 |  |  |     u32 blend_state_bits; | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  |     PortableVertexDeclaration vertex_decl; | 
					
						
							|  |  |  |     VertexShaderUid vs_uid; | 
					
						
							|  |  |  |     GeometryShaderUid gs_uid; | 
					
						
							|  |  |  |     PixelShaderUid ps_uid; | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 15:38:32 +10:00
										 |  |  |   // Number of descriptor sets for game draws.
 | 
					
						
							|  |  |  |   enum | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_PIXEL_SHADER_SAMPLERS + 1, | 
					
						
							|  |  |  |     NUM_GX_DRAW_WITH_BBOX_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1 | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   enum DITRY_FLAG : u32 | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DIRTY_FLAG_VS_UBO = (1 << 0), | 
					
						
							|  |  |  |     DIRTY_FLAG_GS_UBO = (1 << 1), | 
					
						
							|  |  |  |     DIRTY_FLAG_PS_UBO = (1 << 2), | 
					
						
							|  |  |  |     DIRTY_FLAG_PS_SAMPLERS = (1 << 3), | 
					
						
							|  |  |  |     DIRTY_FLAG_PS_SSBO = (1 << 4), | 
					
						
							|  |  |  |     DIRTY_FLAG_DYNAMIC_OFFSETS = (1 << 5), | 
					
						
							|  |  |  |     DIRTY_FLAG_VERTEX_BUFFER = (1 << 6), | 
					
						
							|  |  |  |     DIRTY_FLAG_INDEX_BUFFER = (1 << 7), | 
					
						
							|  |  |  |     DIRTY_FLAG_VIEWPORT = (1 << 8), | 
					
						
							|  |  |  |     DIRTY_FLAG_SCISSOR = (1 << 9), | 
					
						
							|  |  |  |     DIRTY_FLAG_PIPELINE = (1 << 10), | 
					
						
							|  |  |  |     DIRTY_FLAG_DESCRIPTOR_SET_BINDING = (1 << 11), | 
					
						
							|  |  |  |     DIRTY_FLAG_PIPELINE_BINDING = (1 << 12), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:35 +10:00
										 |  |  |     DIRTY_FLAG_ALL_DESCRIPTOR_SETS = DIRTY_FLAG_VS_UBO | DIRTY_FLAG_GS_UBO | DIRTY_FLAG_PS_UBO | | 
					
						
							|  |  |  |                                      DIRTY_FLAG_PS_SAMPLERS | DIRTY_FLAG_PS_SSBO | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   bool Initialize(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Appends the specified pipeline info, combined with the UIDs stored in the class.
 | 
					
						
							|  |  |  |   // The info is here so that we can store variations of a UID, e.g. blend state.
 | 
					
						
							|  |  |  |   void AppendToPipelineUIDCache(const PipelineInfo& info); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Precaches a pipeline based on the UID information.
 | 
					
						
							|  |  |  |   bool PrecachePipelineUID(const SerializedPipelineUID& uid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Obtains a Vulkan pipeline object for the specified pipeline configuration.
 | 
					
						
							|  |  |  |   // Also adds this pipeline configuration to the UID cache if it is not present already.
 | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:35 +10:00
										 |  |  |   VkPipeline GetPipelineAndCacheUID(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Are bounding box ubershaders enabled? If so, we need to ensure the SSBO is set up,
 | 
					
						
							|  |  |  |   // since the bbox writes are determined by a uniform.
 | 
					
						
							|  |  |  |   bool IsSSBODescriptorRequired() const; | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   bool UpdatePipeline(); | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:35 +10:00
										 |  |  |   void UpdatePipelineLayout(); | 
					
						
							|  |  |  |   void UpdatePipelineVertexFormat(); | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  |   bool UpdateDescriptorSet(); | 
					
						
							| 
									
										
										
										
											2016-11-30 23:32:23 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Allocates storage in the uniform buffer of the specified size. If this storage cannot be
 | 
					
						
							|  |  |  |   // allocated immediately, the current command buffer will be submitted and all stage's
 | 
					
						
							|  |  |  |   // constants will be re-uploaded. false will be returned in this case, otherwise true.
 | 
					
						
							|  |  |  |   bool ReserveConstantStorage(); | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  |   void UploadAllConstants(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Which bindings/state has to be updated before the next draw.
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // shader state
 | 
					
						
							|  |  |  |   VertexShaderUid m_vs_uid = {}; | 
					
						
							|  |  |  |   GeometryShaderUid m_gs_uid = {}; | 
					
						
							|  |  |  |   PixelShaderUid m_ps_uid = {}; | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:35 +10:00
										 |  |  |   UberShader::VertexShaderUid m_uber_vs_uid = {}; | 
					
						
							|  |  |  |   UberShader::PixelShaderUid m_uber_ps_uid = {}; | 
					
						
							|  |  |  |   bool m_using_ubershaders = false; | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // pipeline state
 | 
					
						
							|  |  |  |   PipelineInfo m_pipeline_state = {}; | 
					
						
							|  |  |  |   VkPipeline m_pipeline_object = VK_NULL_HANDLE; | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:35 +10:00
										 |  |  |   const VertexFormat* m_vertex_format = nullptr; | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // shader bindings
 | 
					
						
							| 
									
										
										
										
											2016-11-13 15:38:32 +10:00
										 |  |  |   std::array<VkDescriptorSet, NUM_DESCRIPTOR_SET_BIND_POINTS> m_descriptor_sets = {}; | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   struct | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::array<VkDescriptorBufferInfo, NUM_UBO_DESCRIPTOR_SET_BINDINGS> uniform_buffer_bindings = | 
					
						
							|  |  |  |         {}; | 
					
						
							|  |  |  |     std::array<uint32_t, NUM_UBO_DESCRIPTOR_SET_BINDINGS> uniform_buffer_offsets = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS> ps_samplers = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VkDescriptorBufferInfo ps_ssbo = {}; | 
					
						
							|  |  |  |   } m_bindings; | 
					
						
							|  |  |  |   u32 m_num_active_descriptor_sets = 0; | 
					
						
							|  |  |  |   size_t m_uniform_buffer_reserve_size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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<StreamBuffer> m_uniform_stream_buffer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   VkFramebuffer m_framebuffer = VK_NULL_HANDLE; | 
					
						
							| 
									
										
										
										
											2016-09-11 16:37:41 +10:00
										 |  |  |   VkRenderPass m_load_render_pass = VK_NULL_HANDLE; | 
					
						
							|  |  |  |   VkRenderPass m_clear_render_pass = VK_NULL_HANDLE; | 
					
						
							|  |  |  |   VkRenderPass m_current_render_pass = VK_NULL_HANDLE; | 
					
						
							|  |  |  |   VkRect2D m_framebuffer_size = {}; | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   VkRect2D m_framebuffer_render_area = {}; | 
					
						
							|  |  |  |   bool m_bbox_enabled = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // CPU access tracking
 | 
					
						
							|  |  |  |   u32 m_draw_counter = 0; | 
					
						
							|  |  |  |   std::vector<u32> m_cpu_accesses_this_frame; | 
					
						
							|  |  |  |   std::vector<u32> m_scheduled_command_buffer_kicks; | 
					
						
							|  |  |  |   bool m_allow_background_execution = true; | 
					
						
							| 
									
										
										
										
											2016-11-13 18:39:06 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Draw state cache on disk
 | 
					
						
							|  |  |  |   // We don't actually use the value field here, instead we generate the shaders from the uid
 | 
					
						
							|  |  |  |   // on-demand. If all goes well, it should hit the shader and Vulkan pipeline cache, therefore
 | 
					
						
							|  |  |  |   // loading should be reasonably efficient.
 | 
					
						
							|  |  |  |   LinearDiskCache<SerializedPipelineUID, u32> m_uid_cache; | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | }; | 
					
						
							|  |  |  | } |