1 // Copyright (c) 2015- PPSSPP Project. 2 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, version 2.0 or later versions. 6 7 // This program is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 // GNU General Public License 2.0 for more details. 11 12 // A copy of the GPL 2.0 should have been included with the program. 13 // If not, see http://www.gnu.org/licenses/ 14 15 // Official git repository and contact information can be found at 16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. 17 18 #pragma once 19 20 // The Descriptor Set used for the majority of PSP rendering looks like this: 21 // 22 // * binding 0: Texture/Sampler (the PSP texture) 23 // * binding 1: Secondary texture sampler for shader blending 24 // * binding 2: Depal palette 25 // * binding 3: Base Uniform Buffer (includes fragment state) 26 // * binding 4: Light uniform buffer 27 // * binding 5: Bone uniform buffer 28 // * binding 6: Tess data storage buffer 29 // 30 // All shaders conform to this layout, so they are all compatible with the same descriptor set. 31 // The format of the various uniform buffers may vary though - vertex shaders that don't skin 32 // won't get any bone data, etc. 33 34 #include "Common/Data/Collections/Hashmaps.h" 35 36 #include "GPU/Vulkan/VulkanUtil.h" 37 38 #include "GPU/GPUState.h" 39 #include "GPU/Common/GPUDebugInterface.h" 40 #include "GPU/Common/IndexGenerator.h" 41 #include "GPU/Common/VertexDecoderCommon.h" 42 #include "GPU/Common/DrawEngineCommon.h" 43 #include "GPU/Common/GPUStateUtils.h" 44 #include "GPU/Vulkan/StateMappingVulkan.h" 45 46 struct DecVtxFormat; 47 struct UVScale; 48 49 class ShaderManagerVulkan; 50 class PipelineManagerVulkan; 51 class TextureCacheVulkan; 52 class FramebufferManagerVulkan; 53 54 class VulkanContext; 55 class VulkanPushBuffer; 56 struct VulkanPipeline; 57 58 struct DrawEngineVulkanStats { 59 int pushUBOSpaceUsed; 60 int pushVertexSpaceUsed; 61 int pushIndexSpaceUsed; 62 }; 63 64 enum { 65 VAIVULKAN_FLAG_VERTEXFULLALPHA = 1, 66 }; 67 68 // Try to keep this POD. 69 class VertexArrayInfoVulkan { 70 public: VertexArrayInfoVulkan()71 VertexArrayInfoVulkan() { 72 lastFrame = gpuStats.numFlips; 73 } 74 // No destructor needed - we always fully wipe. 75 76 enum VAIStatus : uint8_t { 77 VAI_NEW, 78 VAI_HASHING, 79 VAI_RELIABLE, // cache, don't hash 80 VAI_UNRELIABLE, // never cache 81 }; 82 83 uint64_t hash; 84 u32 minihash; 85 86 // These will probably always be the same, but whatever. 87 VkBuffer vb = VK_NULL_HANDLE; 88 VkBuffer ib = VK_NULL_HANDLE; 89 // Offsets into the cache buffer. 90 uint32_t vbOffset = 0; 91 uint32_t ibOffset = 0; 92 93 // Precalculated parameter for vkDrawIndexed 94 u16 numVerts = 0; 95 u16 maxIndex = 0; 96 s8 prim = GE_PRIM_INVALID; 97 VAIStatus status = VAI_NEW; 98 99 // ID information 100 int numDraws = 0; 101 int numFrames = 0; 102 int lastFrame; // So that we can forget. 103 u16 drawsUntilNextFullHash = 0; 104 u8 flags = 0; 105 }; 106 107 class VulkanRenderManager; 108 109 class TessellationDataTransferVulkan : public TessellationDataTransfer { 110 public: TessellationDataTransferVulkan(VulkanContext * vulkan)111 TessellationDataTransferVulkan(VulkanContext *vulkan) : vulkan_(vulkan) {} 112 SetPushBuffer(VulkanPushBuffer * push)113 void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } 114 // Send spline/bezier's control points and weights to vertex shader through structured shader buffer. 115 void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override; GetBufferInfo()116 const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; } 117 private: 118 VulkanContext *vulkan_; 119 VulkanPushBuffer *push_; // Updated each frame. 120 VkDescriptorBufferInfo bufInfo_[3]{}; 121 }; 122 123 // Handles transform, lighting and drawing. 124 class DrawEngineVulkan : public DrawEngineCommon { 125 public: 126 DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *draw); 127 virtual ~DrawEngineVulkan(); 128 SetShaderManager(ShaderManagerVulkan * shaderManager)129 void SetShaderManager(ShaderManagerVulkan *shaderManager) { 130 shaderManager_ = shaderManager; 131 } SetPipelineManager(PipelineManagerVulkan * pipelineManager)132 void SetPipelineManager(PipelineManagerVulkan *pipelineManager) { 133 pipelineManager_ = pipelineManager; 134 } SetTextureCache(TextureCacheVulkan * textureCache)135 void SetTextureCache(TextureCacheVulkan *textureCache) { 136 textureCache_ = textureCache; 137 } SetFramebufferManager(FramebufferManagerVulkan * fbManager)138 void SetFramebufferManager(FramebufferManagerVulkan *fbManager) { 139 framebufferManager_ = fbManager; 140 } 141 142 void DeviceLost(); 143 void DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw); 144 145 // So that this can be inlined Flush()146 void Flush() { 147 if (!numDrawCalls) 148 return; 149 DoFlush(); 150 } 151 FinishDeferred()152 void FinishDeferred() { 153 if (!numDrawCalls) 154 return; 155 // Decode any pending vertices. And also flush while we're at it, for simplicity. 156 // It might be possible to only decode like in the other backends, but meh, it can't matter. 157 // Issue #10095 has a nice example of where this is required. 158 DoFlush(); 159 } 160 DispatchFlush()161 void DispatchFlush() override { Flush(); } 162 GetPipelineLayout()163 VkPipelineLayout GetPipelineLayout() const { 164 return pipelineLayout_; 165 } 166 167 void BeginFrame(); 168 void EndFrame(); 169 170 void DirtyAllUBOs(); 171 DirtyPipeline()172 void DirtyPipeline() { 173 lastPipeline_ = nullptr; 174 } 175 GetPushBufferForTextureData()176 VulkanPushBuffer *GetPushBufferForTextureData() { 177 return frame_[vulkan_->GetCurFrame()].pushUBO; 178 } 179 180 // Only use Allocate on this one. GetPushBufferLocal()181 VulkanPushBuffer *GetPushBufferLocal() { 182 return frame_[vulkan_->GetCurFrame()].pushLocal; 183 } 184 GetStats()185 const DrawEngineVulkanStats &GetStats() const { 186 return stats_; 187 } 188 189 void SetLineWidth(float lineWidth); SetDepalTexture(VkImageView depal)190 void SetDepalTexture(VkImageView depal) { 191 if (boundDepal_ != depal) { 192 boundDepal_ = depal; 193 gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); 194 } 195 } 196 197 private: 198 struct FrameData; 199 void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant); 200 void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState); 201 void BindShaderBlendTex(); 202 void ResetFramebufferRead(); 203 204 void InitDeviceObjects(); 205 void DestroyDeviceObjects(); 206 207 void DecodeVertsToPushBuffer(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf); 208 VkResult RecreateDescriptorPool(FrameData &frame, int newSize); 209 210 void DoFlush(); 211 void UpdateUBOs(FrameData *frame); 212 213 VkDescriptorSet GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess); 214 215 VulkanContext *vulkan_; 216 Draw::DrawContext *draw_; 217 218 // We use a single descriptor set layout for all PSP draws. 219 VkDescriptorSetLayout descriptorSetLayout_; 220 VkPipelineLayout pipelineLayout_; 221 VulkanPipeline *lastPipeline_; 222 VkDescriptorSet lastDs_ = VK_NULL_HANDLE; 223 224 // Secondary texture for shader blending 225 VkImageView boundSecondary_ = VK_NULL_HANDLE; 226 VkImageView boundDepal_ = VK_NULL_HANDLE; 227 VkSampler samplerSecondary_ = VK_NULL_HANDLE; // This one is actually never used since we use fetch. 228 229 PrehashMap<VertexArrayInfoVulkan *, nullptr> vai_; 230 VulkanPushBuffer *vertexCache_; 231 int descDecimationCounter_ = 0; 232 233 struct DescriptorSetKey { 234 VkImageView imageView_; 235 VkImageView secondaryImageView_; 236 VkImageView depalImageView_; 237 VkSampler sampler_; 238 VkBuffer base_, light_, bone_; // All three UBO slots will be set to this. This will usually be identical 239 // for all draws in a frame, except when the buffer has to grow. 240 }; 241 242 // We alternate between these. 243 struct FrameData { FrameDataFrameData244 FrameData() : descSets(512) {} 245 246 VkDescriptorPool descPool = VK_NULL_HANDLE; 247 int descCount = 0; 248 int descPoolSize = 256; // We double this before we allocate so we initialize this to half the size we want. 249 250 VulkanPushBuffer *pushUBO = nullptr; 251 VulkanPushBuffer *pushVertex = nullptr; 252 VulkanPushBuffer *pushIndex = nullptr; 253 254 // Special push buffer in GPU local memory, for texture data conversion and similar tasks. 255 VulkanPushBuffer *pushLocal; 256 257 // We do rolling allocation and reset instead of caching across frames. That we might do later. 258 DenseHashMap<DescriptorSetKey, VkDescriptorSet, (VkDescriptorSet)VK_NULL_HANDLE> descSets; 259 260 void Destroy(VulkanContext *vulkan); 261 }; 262 263 GEPrimitiveType lastPrim_ = GE_PRIM_INVALID; 264 FrameData frame_[VulkanContext::MAX_INFLIGHT_FRAMES]; 265 266 // Other 267 ShaderManagerVulkan *shaderManager_ = nullptr; 268 PipelineManagerVulkan *pipelineManager_ = nullptr; 269 TextureCacheVulkan *textureCache_ = nullptr; 270 FramebufferManagerVulkan *framebufferManager_ = nullptr; 271 272 // State cache 273 uint64_t dirtyUniforms_; 274 uint32_t baseUBOOffset; 275 uint32_t lightUBOOffset; 276 uint32_t boneUBOOffset; 277 VkBuffer baseBuf, lightBuf, boneBuf; 278 VkImageView imageView = VK_NULL_HANDLE; 279 VkSampler sampler = VK_NULL_HANDLE; 280 281 // For null texture 282 VkSampler nullSampler_ = VK_NULL_HANDLE; 283 284 DrawEngineVulkanStats stats_{}; 285 286 VulkanPipelineRasterStateKey pipelineKey_{}; 287 VulkanDynamicState dynState_{}; 288 289 int tessOffset_ = 0; 290 291 // Hardware tessellation 292 TessellationDataTransferVulkan *tessDataTransferVulkan; 293 294 int lastRenderStepId_ = -1; 295 }; 296