diff options
| -rw-r--r-- | src/video_core/dirty_flags.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/dirty_flags.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state_tracker.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state_tracker.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 46 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.h | 54 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 31 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.h | 30 |
9 files changed, 114 insertions, 64 deletions
diff --git a/src/video_core/dirty_flags.cpp b/src/video_core/dirty_flags.cpp index 7149af290..b1be065c3 100644 --- a/src/video_core/dirty_flags.cpp +++ b/src/video_core/dirty_flags.cpp | |||
| @@ -58,6 +58,11 @@ void SetupDirtyRenderTargets(Maxwell3D::DirtyState::Tables& tables) { | |||
| 58 | FillBlock(table, OFF(zeta), NUM(zeta), flag); | 58 | FillBlock(table, OFF(zeta), NUM(zeta), flag); |
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | |||
| 62 | void SetupDirtyShaders(Maxwell3D::DirtyState::Tables& tables) { | ||
| 63 | FillBlock(tables[0], OFF(shader_config[0]), | ||
| 64 | NUM(shader_config[0]) * Maxwell3D::Regs::MaxShaderProgram, Shaders); | ||
| 65 | } | ||
| 61 | } // Anonymous namespace | 66 | } // Anonymous namespace |
| 62 | 67 | ||
| 63 | void SetupDirtyFlags(Maxwell3D::DirtyState::Tables& tables) { | 68 | void SetupDirtyFlags(Maxwell3D::DirtyState::Tables& tables) { |
| @@ -65,6 +70,7 @@ void SetupDirtyFlags(Maxwell3D::DirtyState::Tables& tables) { | |||
| 65 | SetupIndexBuffer(tables); | 70 | SetupIndexBuffer(tables); |
| 66 | SetupDirtyDescriptors(tables); | 71 | SetupDirtyDescriptors(tables); |
| 67 | SetupDirtyRenderTargets(tables); | 72 | SetupDirtyRenderTargets(tables); |
| 73 | SetupDirtyShaders(tables); | ||
| 68 | } | 74 | } |
| 69 | 75 | ||
| 70 | } // namespace VideoCommon::Dirty | 76 | } // namespace VideoCommon::Dirty |
diff --git a/src/video_core/dirty_flags.h b/src/video_core/dirty_flags.h index 702688ace..504465d3f 100644 --- a/src/video_core/dirty_flags.h +++ b/src/video_core/dirty_flags.h | |||
| @@ -36,6 +36,8 @@ enum : u8 { | |||
| 36 | 36 | ||
| 37 | IndexBuffer, | 37 | IndexBuffer, |
| 38 | 38 | ||
| 39 | Shaders, | ||
| 40 | |||
| 39 | LastCommonEntry, | 41 | LastCommonEntry, |
| 40 | }; | 42 | }; |
| 41 | 43 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 3551dbdcc..dd1937863 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -635,7 +635,7 @@ void RasterizerOpenGL::SyncDepthClamp() { | |||
| 635 | 635 | ||
| 636 | void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) { | 636 | void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) { |
| 637 | auto& flags = maxwell3d.dirty.flags; | 637 | auto& flags = maxwell3d.dirty.flags; |
| 638 | if (!flags[Dirty::ClipDistances] && !flags[Dirty::Shaders]) { | 638 | if (!flags[Dirty::ClipDistances] && !flags[VideoCommon::Dirty::Shaders]) { |
| 639 | return; | 639 | return; |
| 640 | } | 640 | } |
| 641 | flags[Dirty::ClipDistances] = false; | 641 | flags[Dirty::ClipDistances] = false; |
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp index dbdf5230f..586da84e3 100644 --- a/src/video_core/renderer_opengl/gl_state_tracker.cpp +++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp | |||
| @@ -83,11 +83,6 @@ void SetupDirtyScissors(Tables& tables) { | |||
| 83 | FillBlock(tables[1], OFF(scissor_test), NUM(scissor_test), Scissors); | 83 | FillBlock(tables[1], OFF(scissor_test), NUM(scissor_test), Scissors); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | void SetupDirtyShaders(Tables& tables) { | ||
| 87 | FillBlock(tables[0], OFF(shader_config[0]), NUM(shader_config[0]) * Regs::MaxShaderProgram, | ||
| 88 | Shaders); | ||
| 89 | } | ||
| 90 | |||
| 91 | void SetupDirtyPolygonModes(Tables& tables) { | 86 | void SetupDirtyPolygonModes(Tables& tables) { |
| 92 | tables[0][OFF(polygon_mode_front)] = PolygonModeFront; | 87 | tables[0][OFF(polygon_mode_front)] = PolygonModeFront; |
| 93 | tables[0][OFF(polygon_mode_back)] = PolygonModeBack; | 88 | tables[0][OFF(polygon_mode_back)] = PolygonModeBack; |
| @@ -217,7 +212,6 @@ StateTracker::StateTracker(Tegra::GPU& gpu) : flags{gpu.Maxwell3D().dirty.flags} | |||
| 217 | SetupDirtyScissors(tables); | 212 | SetupDirtyScissors(tables); |
| 218 | SetupDirtyVertexInstances(tables); | 213 | SetupDirtyVertexInstances(tables); |
| 219 | SetupDirtyVertexFormat(tables); | 214 | SetupDirtyVertexFormat(tables); |
| 220 | SetupDirtyShaders(tables); | ||
| 221 | SetupDirtyPolygonModes(tables); | 215 | SetupDirtyPolygonModes(tables); |
| 222 | SetupDirtyDepthTest(tables); | 216 | SetupDirtyDepthTest(tables); |
| 223 | SetupDirtyStencilTest(tables); | 217 | SetupDirtyStencilTest(tables); |
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.h b/src/video_core/renderer_opengl/gl_state_tracker.h index 94c905116..5864c7c07 100644 --- a/src/video_core/renderer_opengl/gl_state_tracker.h +++ b/src/video_core/renderer_opengl/gl_state_tracker.h | |||
| @@ -52,7 +52,6 @@ enum : u8 { | |||
| 52 | BlendState0, | 52 | BlendState0, |
| 53 | BlendState7 = BlendState0 + 7, | 53 | BlendState7 = BlendState0 + 7, |
| 54 | 54 | ||
| 55 | Shaders, | ||
| 56 | ClipDistances, | 55 | ClipDistances, |
| 57 | 56 | ||
| 58 | PolygonModes, | 57 | PolygonModes, |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 2bc1f67ae..100a5e07a 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -125,13 +125,12 @@ GraphicsPipeline::GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d_, | |||
| 125 | VKUpdateDescriptorQueue& update_descriptor_queue_, | 125 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 126 | Common::ThreadWorker* worker_thread, | 126 | Common::ThreadWorker* worker_thread, |
| 127 | RenderPassCache& render_pass_cache, | 127 | RenderPassCache& render_pass_cache, |
| 128 | const FixedPipelineState& state_, | 128 | const GraphicsPipelineCacheKey& key_, |
| 129 | std::array<vk::ShaderModule, NUM_STAGES> stages, | 129 | std::array<vk::ShaderModule, NUM_STAGES> stages, |
| 130 | const std::array<const Shader::Info*, NUM_STAGES>& infos) | 130 | const std::array<const Shader::Info*, NUM_STAGES>& infos) |
| 131 | : maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, texture_cache{texture_cache_}, | 131 | : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, texture_cache{texture_cache_}, |
| 132 | buffer_cache{buffer_cache_}, scheduler{scheduler_}, | 132 | buffer_cache{buffer_cache_}, scheduler{scheduler_}, |
| 133 | update_descriptor_queue{update_descriptor_queue_}, state{state_}, spv_modules{ | 133 | update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} { |
| 134 | std::move(stages)} { | ||
| 135 | std::ranges::transform(infos, stage_infos.begin(), | 134 | std::ranges::transform(infos, stage_infos.begin(), |
| 136 | [](const Shader::Info* info) { return info ? *info : Shader::Info{}; }); | 135 | [](const Shader::Info* info) { return info ? *info : Shader::Info{}; }); |
| 137 | 136 | ||
| @@ -144,7 +143,7 @@ GraphicsPipeline::GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d_, | |||
| 144 | pipeline_layout = builder.CreatePipelineLayout(set_layout); | 143 | pipeline_layout = builder.CreatePipelineLayout(set_layout); |
| 145 | descriptor_update_template = builder.CreateTemplate(set_layout, *pipeline_layout); | 144 | descriptor_update_template = builder.CreateTemplate(set_layout, *pipeline_layout); |
| 146 | 145 | ||
| 147 | const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(state))}; | 146 | const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state))}; |
| 148 | MakePipeline(device, render_pass); | 147 | MakePipeline(device, render_pass); |
| 149 | 148 | ||
| 150 | std::lock_guard lock{build_mutex}; | 149 | std::lock_guard lock{build_mutex}; |
| @@ -158,6 +157,11 @@ GraphicsPipeline::GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d_, | |||
| 158 | } | 157 | } |
| 159 | } | 158 | } |
| 160 | 159 | ||
| 160 | void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) { | ||
| 161 | transition_keys.push_back(transition->key); | ||
| 162 | transitions.push_back(transition); | ||
| 163 | } | ||
| 164 | |||
| 161 | void GraphicsPipeline::Configure(bool is_indexed) { | 165 | void GraphicsPipeline::Configure(bool is_indexed) { |
| 162 | static constexpr size_t max_images_elements = 64; | 166 | static constexpr size_t max_images_elements = 64; |
| 163 | std::array<ImageId, max_images_elements> image_view_ids; | 167 | std::array<ImageId, max_images_elements> image_view_ids; |
| @@ -294,12 +298,12 @@ void GraphicsPipeline::Configure(bool is_indexed) { | |||
| 294 | void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pass) { | 298 | void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pass) { |
| 295 | FixedPipelineState::DynamicState dynamic{}; | 299 | FixedPipelineState::DynamicState dynamic{}; |
| 296 | if (!device.IsExtExtendedDynamicStateSupported()) { | 300 | if (!device.IsExtExtendedDynamicStateSupported()) { |
| 297 | dynamic = state.dynamic_state; | 301 | dynamic = key.state.dynamic_state; |
| 298 | } | 302 | } |
| 299 | static_vector<VkVertexInputBindingDescription, 32> vertex_bindings; | 303 | static_vector<VkVertexInputBindingDescription, 32> vertex_bindings; |
| 300 | static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors; | 304 | static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors; |
| 301 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 305 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 302 | const bool instanced = state.binding_divisors[index] != 0; | 306 | const bool instanced = key.state.binding_divisors[index] != 0; |
| 303 | const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; | 307 | const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; |
| 304 | vertex_bindings.push_back({ | 308 | vertex_bindings.push_back({ |
| 305 | .binding = static_cast<u32>(index), | 309 | .binding = static_cast<u32>(index), |
| @@ -309,14 +313,14 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 309 | if (instanced) { | 313 | if (instanced) { |
| 310 | vertex_binding_divisors.push_back({ | 314 | vertex_binding_divisors.push_back({ |
| 311 | .binding = static_cast<u32>(index), | 315 | .binding = static_cast<u32>(index), |
| 312 | .divisor = state.binding_divisors[index], | 316 | .divisor = key.state.binding_divisors[index], |
| 313 | }); | 317 | }); |
| 314 | } | 318 | } |
| 315 | } | 319 | } |
| 316 | static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes; | 320 | static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes; |
| 317 | const auto& input_attributes = stage_infos[0].input_generics; | 321 | const auto& input_attributes = stage_infos[0].input_generics; |
| 318 | for (size_t index = 0; index < state.attributes.size(); ++index) { | 322 | for (size_t index = 0; index < key.state.attributes.size(); ++index) { |
| 319 | const auto& attribute = state.attributes[index]; | 323 | const auto& attribute = key.state.attributes[index]; |
| 320 | if (!attribute.enabled || !input_attributes[index].used) { | 324 | if (!attribute.enabled || !input_attributes[index].used) { |
| 321 | continue; | 325 | continue; |
| 322 | } | 326 | } |
| @@ -345,7 +349,7 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 345 | if (!vertex_binding_divisors.empty()) { | 349 | if (!vertex_binding_divisors.empty()) { |
| 346 | vertex_input_ci.pNext = &input_divisor_ci; | 350 | vertex_input_ci.pNext = &input_divisor_ci; |
| 347 | } | 351 | } |
| 348 | auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, state.topology); | 352 | auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, key.state.topology); |
| 349 | if (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { | 353 | if (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { |
| 350 | if (!spv_modules[1] && !spv_modules[2]) { | 354 | if (!spv_modules[1] && !spv_modules[2]) { |
| 351 | LOG_WARNING(Render_Vulkan, "Patch topology used without tessellation, using points"); | 355 | LOG_WARNING(Render_Vulkan, "Patch topology used without tessellation, using points"); |
| @@ -357,14 +361,14 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 357 | .pNext = nullptr, | 361 | .pNext = nullptr, |
| 358 | .flags = 0, | 362 | .flags = 0, |
| 359 | .topology = input_assembly_topology, | 363 | .topology = input_assembly_topology, |
| 360 | .primitiveRestartEnable = state.primitive_restart_enable != 0 && | 364 | .primitiveRestartEnable = key.state.primitive_restart_enable != 0 && |
| 361 | SupportsPrimitiveRestart(input_assembly_topology), | 365 | SupportsPrimitiveRestart(input_assembly_topology), |
| 362 | }; | 366 | }; |
| 363 | const VkPipelineTessellationStateCreateInfo tessellation_ci{ | 367 | const VkPipelineTessellationStateCreateInfo tessellation_ci{ |
| 364 | .sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, | 368 | .sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, |
| 365 | .pNext = nullptr, | 369 | .pNext = nullptr, |
| 366 | .flags = 0, | 370 | .flags = 0, |
| 367 | .patchControlPoints = state.patch_control_points_minus_one.Value() + 1, | 371 | .patchControlPoints = key.state.patch_control_points_minus_one.Value() + 1, |
| 368 | }; | 372 | }; |
| 369 | VkPipelineViewportStateCreateInfo viewport_ci{ | 373 | VkPipelineViewportStateCreateInfo viewport_ci{ |
| 370 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | 374 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, |
| @@ -376,7 +380,7 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 376 | .pScissors = nullptr, | 380 | .pScissors = nullptr, |
| 377 | }; | 381 | }; |
| 378 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; | 382 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; |
| 379 | std::ranges::transform(state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); | 383 | std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); |
| 380 | VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ | 384 | VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ |
| 381 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, | 385 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, |
| 382 | .pNext = nullptr, | 386 | .pNext = nullptr, |
| @@ -393,15 +397,15 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 393 | .pNext = nullptr, | 397 | .pNext = nullptr, |
| 394 | .flags = 0, | 398 | .flags = 0, |
| 395 | .depthClampEnable = | 399 | .depthClampEnable = |
| 396 | static_cast<VkBool32>(state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE), | 400 | static_cast<VkBool32>(key.state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE), |
| 397 | .rasterizerDiscardEnable = | 401 | .rasterizerDiscardEnable = |
| 398 | static_cast<VkBool32>(state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), | 402 | static_cast<VkBool32>(key.state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), |
| 399 | .polygonMode = | 403 | .polygonMode = |
| 400 | MaxwellToVK::PolygonMode(FixedPipelineState::UnpackPolygonMode(state.polygon_mode)), | 404 | MaxwellToVK::PolygonMode(FixedPipelineState::UnpackPolygonMode(key.state.polygon_mode)), |
| 401 | .cullMode = static_cast<VkCullModeFlags>( | 405 | .cullMode = static_cast<VkCullModeFlags>( |
| 402 | dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE), | 406 | dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE), |
| 403 | .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), | 407 | .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), |
| 404 | .depthBiasEnable = state.depth_bias_enable, | 408 | .depthBiasEnable = key.state.depth_bias_enable, |
| 405 | .depthBiasConstantFactor = 0.0f, | 409 | .depthBiasConstantFactor = 0.0f, |
| 406 | .depthBiasClamp = 0.0f, | 410 | .depthBiasClamp = 0.0f, |
| 407 | .depthBiasSlopeFactor = 0.0f, | 411 | .depthBiasSlopeFactor = 0.0f, |
| @@ -411,7 +415,7 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 411 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | 415 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| 412 | .pNext = nullptr, | 416 | .pNext = nullptr, |
| 413 | .flags = 0, | 417 | .flags = 0, |
| 414 | .rasterizationSamples = MaxwellToVK::MsaaMode(state.msaa_mode), | 418 | .rasterizationSamples = MaxwellToVK::MsaaMode(key.state.msaa_mode), |
| 415 | .sampleShadingEnable = VK_FALSE, | 419 | .sampleShadingEnable = VK_FALSE, |
| 416 | .minSampleShading = 0.0f, | 420 | .minSampleShading = 0.0f, |
| 417 | .pSampleMask = nullptr, | 421 | .pSampleMask = nullptr, |
| @@ -435,7 +439,7 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 435 | .maxDepthBounds = 0.0f, | 439 | .maxDepthBounds = 0.0f, |
| 436 | }; | 440 | }; |
| 437 | static_vector<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; | 441 | static_vector<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; |
| 438 | const size_t num_attachments{NumAttachments(state)}; | 442 | const size_t num_attachments{NumAttachments(key.state)}; |
| 439 | for (size_t index = 0; index < num_attachments; ++index) { | 443 | for (size_t index = 0; index < num_attachments; ++index) { |
| 440 | static constexpr std::array mask_table{ | 444 | static constexpr std::array mask_table{ |
| 441 | VK_COLOR_COMPONENT_R_BIT, | 445 | VK_COLOR_COMPONENT_R_BIT, |
| @@ -443,7 +447,7 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 443 | VK_COLOR_COMPONENT_B_BIT, | 447 | VK_COLOR_COMPONENT_B_BIT, |
| 444 | VK_COLOR_COMPONENT_A_BIT, | 448 | VK_COLOR_COMPONENT_A_BIT, |
| 445 | }; | 449 | }; |
| 446 | const auto& blend{state.attachments[index]}; | 450 | const auto& blend{key.state.attachments[index]}; |
| 447 | const std::array mask{blend.Mask()}; | 451 | const std::array mask{blend.Mask()}; |
| 448 | VkColorComponentFlags write_mask{}; | 452 | VkColorComponentFlags write_mask{}; |
| 449 | for (size_t i = 0; i < mask_table.size(); ++i) { | 453 | for (size_t i = 0; i < mask_table.size(); ++i) { |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 7d14d2378..fd787840b 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h | |||
| @@ -4,10 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 7 | #include <array> | 8 | #include <array> |
| 8 | #include <atomic> | 9 | #include <atomic> |
| 9 | #include <condition_variable> | 10 | #include <condition_variable> |
| 10 | #include <mutex> | 11 | #include <mutex> |
| 12 | #include <type_traits> | ||
| 11 | 13 | ||
| 12 | #include "common/thread_worker.h" | 14 | #include "common/thread_worker.h" |
| 13 | #include "shader_recompiler/shader_info.h" | 15 | #include "shader_recompiler/shader_info.h" |
| @@ -20,6 +22,39 @@ | |||
| 20 | 22 | ||
| 21 | namespace Vulkan { | 23 | namespace Vulkan { |
| 22 | 24 | ||
| 25 | struct GraphicsPipelineCacheKey { | ||
| 26 | std::array<u128, 6> unique_hashes; | ||
| 27 | FixedPipelineState state; | ||
| 28 | |||
| 29 | size_t Hash() const noexcept; | ||
| 30 | |||
| 31 | bool operator==(const GraphicsPipelineCacheKey& rhs) const noexcept; | ||
| 32 | |||
| 33 | bool operator!=(const GraphicsPipelineCacheKey& rhs) const noexcept { | ||
| 34 | return !operator==(rhs); | ||
| 35 | } | ||
| 36 | |||
| 37 | size_t Size() const noexcept { | ||
| 38 | return sizeof(unique_hashes) + state.Size(); | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>); | ||
| 42 | static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>); | ||
| 43 | static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>); | ||
| 44 | |||
| 45 | } // namespace Vulkan | ||
| 46 | |||
| 47 | namespace std { | ||
| 48 | template <> | ||
| 49 | struct hash<Vulkan::GraphicsPipelineCacheKey> { | ||
| 50 | size_t operator()(const Vulkan::GraphicsPipelineCacheKey& k) const noexcept { | ||
| 51 | return k.Hash(); | ||
| 52 | } | ||
| 53 | }; | ||
| 54 | } // namespace std | ||
| 55 | |||
| 56 | namespace Vulkan { | ||
| 57 | |||
| 23 | class Device; | 58 | class Device; |
| 24 | class RenderPassCache; | 59 | class RenderPassCache; |
| 25 | class VKScheduler; | 60 | class VKScheduler; |
| @@ -35,7 +70,8 @@ public: | |||
| 35 | const Device& device, VKDescriptorPool& descriptor_pool, | 70 | const Device& device, VKDescriptorPool& descriptor_pool, |
| 36 | VKUpdateDescriptorQueue& update_descriptor_queue, | 71 | VKUpdateDescriptorQueue& update_descriptor_queue, |
| 37 | Common::ThreadWorker* worker_thread, | 72 | Common::ThreadWorker* worker_thread, |
| 38 | RenderPassCache& render_pass_cache, const FixedPipelineState& state, | 73 | RenderPassCache& render_pass_cache, |
| 74 | const GraphicsPipelineCacheKey& key, | ||
| 39 | std::array<vk::ShaderModule, NUM_STAGES> stages, | 75 | std::array<vk::ShaderModule, NUM_STAGES> stages, |
| 40 | const std::array<const Shader::Info*, NUM_STAGES>& infos); | 76 | const std::array<const Shader::Info*, NUM_STAGES>& infos); |
| 41 | 77 | ||
| @@ -47,16 +83,30 @@ public: | |||
| 47 | GraphicsPipeline& operator=(const GraphicsPipeline&) = delete; | 83 | GraphicsPipeline& operator=(const GraphicsPipeline&) = delete; |
| 48 | GraphicsPipeline(const GraphicsPipeline&) = delete; | 84 | GraphicsPipeline(const GraphicsPipeline&) = delete; |
| 49 | 85 | ||
| 86 | void AddTransition(GraphicsPipeline* transition); | ||
| 87 | |||
| 88 | GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept { | ||
| 89 | if (key == current_key) { | ||
| 90 | return this; | ||
| 91 | } | ||
| 92 | const auto it{std::find(transition_keys.begin(), transition_keys.end(), current_key)}; | ||
| 93 | return it != transition_keys.end() ? transitions[std::distance(transition_keys.begin(), it)] | ||
| 94 | : nullptr; | ||
| 95 | } | ||
| 96 | |||
| 50 | private: | 97 | private: |
| 51 | void MakePipeline(const Device& device, VkRenderPass render_pass); | 98 | void MakePipeline(const Device& device, VkRenderPass render_pass); |
| 52 | 99 | ||
| 100 | const GraphicsPipelineCacheKey key; | ||
| 53 | Tegra::Engines::Maxwell3D& maxwell3d; | 101 | Tegra::Engines::Maxwell3D& maxwell3d; |
| 54 | Tegra::MemoryManager& gpu_memory; | 102 | Tegra::MemoryManager& gpu_memory; |
| 55 | TextureCache& texture_cache; | 103 | TextureCache& texture_cache; |
| 56 | BufferCache& buffer_cache; | 104 | BufferCache& buffer_cache; |
| 57 | VKScheduler& scheduler; | 105 | VKScheduler& scheduler; |
| 58 | VKUpdateDescriptorQueue& update_descriptor_queue; | 106 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 59 | const FixedPipelineState state; | 107 | |
| 108 | std::vector<GraphicsPipelineCacheKey> transition_keys; | ||
| 109 | std::vector<GraphicsPipeline*> transitions; | ||
| 60 | 110 | ||
| 61 | std::array<vk::ShaderModule, NUM_STAGES> spv_modules; | 111 | std::array<vk::ShaderModule, NUM_STAGES> spv_modules; |
| 62 | std::array<Shader::Info, NUM_STAGES> stage_infos; | 112 | std::array<Shader::Info, NUM_STAGES> stage_infos; |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 4317b2ac7..2bd870060 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "shader_recompiler/frontend/maxwell/control_flow.h" | 21 | #include "shader_recompiler/frontend/maxwell/control_flow.h" |
| 22 | #include "shader_recompiler/frontend/maxwell/program.h" | 22 | #include "shader_recompiler/frontend/maxwell/program.h" |
| 23 | #include "shader_recompiler/program_header.h" | 23 | #include "shader_recompiler/program_header.h" |
| 24 | #include "video_core/dirty_flags.h" | ||
| 24 | #include "video_core/engines/kepler_compute.h" | 25 | #include "video_core/engines/kepler_compute.h" |
| 25 | #include "video_core/engines/maxwell_3d.h" | 26 | #include "video_core/engines/maxwell_3d.h" |
| 26 | #include "video_core/memory_manager.h" | 27 | #include "video_core/memory_manager.h" |
| @@ -700,17 +701,28 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() { | |||
| 700 | MICROPROFILE_SCOPE(Vulkan_PipelineCache); | 701 | MICROPROFILE_SCOPE(Vulkan_PipelineCache); |
| 701 | 702 | ||
| 702 | if (!RefreshStages()) { | 703 | if (!RefreshStages()) { |
| 704 | current_pipeline = nullptr; | ||
| 703 | return nullptr; | 705 | return nullptr; |
| 704 | } | 706 | } |
| 705 | graphics_key.state.Refresh(maxwell3d, device.IsExtExtendedDynamicStateSupported()); | 707 | graphics_key.state.Refresh(maxwell3d, device.IsExtExtendedDynamicStateSupported()); |
| 706 | 708 | ||
| 709 | if (current_pipeline) { | ||
| 710 | GraphicsPipeline* const next{current_pipeline->Next(graphics_key)}; | ||
| 711 | if (next) { | ||
| 712 | current_pipeline = next; | ||
| 713 | return current_pipeline; | ||
| 714 | } | ||
| 715 | } | ||
| 707 | const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)}; | 716 | const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)}; |
| 708 | auto& pipeline{pair->second}; | 717 | auto& pipeline{pair->second}; |
| 709 | if (!is_new) { | 718 | if (is_new) { |
| 710 | return pipeline.get(); | 719 | pipeline = CreateGraphicsPipeline(); |
| 711 | } | 720 | } |
| 712 | pipeline = CreateGraphicsPipeline(); | 721 | if (current_pipeline) { |
| 713 | return pipeline.get(); | 722 | current_pipeline->AddTransition(pipeline.get()); |
| 723 | } | ||
| 724 | current_pipeline = pipeline.get(); | ||
| 725 | return current_pipeline; | ||
| 714 | } | 726 | } |
| 715 | 727 | ||
| 716 | ComputePipeline* PipelineCache::CurrentComputePipeline() { | 728 | ComputePipeline* PipelineCache::CurrentComputePipeline() { |
| @@ -743,6 +755,12 @@ ComputePipeline* PipelineCache::CurrentComputePipeline() { | |||
| 743 | } | 755 | } |
| 744 | 756 | ||
| 745 | bool PipelineCache::RefreshStages() { | 757 | bool PipelineCache::RefreshStages() { |
| 758 | auto& dirty{maxwell3d.dirty.flags}; | ||
| 759 | if (!dirty[VideoCommon::Dirty::Shaders]) { | ||
| 760 | return last_valid_shaders; | ||
| 761 | } | ||
| 762 | dirty[VideoCommon::Dirty::Shaders] = false; | ||
| 763 | |||
| 746 | const GPUVAddr base_addr{maxwell3d.regs.code_address.CodeAddress()}; | 764 | const GPUVAddr base_addr{maxwell3d.regs.code_address.CodeAddress()}; |
| 747 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | 765 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { |
| 748 | if (!maxwell3d.regs.IsShaderConfigEnabled(index)) { | 766 | if (!maxwell3d.regs.IsShaderConfigEnabled(index)) { |
| @@ -755,6 +773,7 @@ bool PipelineCache::RefreshStages() { | |||
| 755 | const std::optional<VAddr> cpu_shader_addr{gpu_memory.GpuToCpuAddress(shader_addr)}; | 773 | const std::optional<VAddr> cpu_shader_addr{gpu_memory.GpuToCpuAddress(shader_addr)}; |
| 756 | if (!cpu_shader_addr) { | 774 | if (!cpu_shader_addr) { |
| 757 | LOG_ERROR(Render_Vulkan, "Invalid GPU address for shader 0x{:016x}", shader_addr); | 775 | LOG_ERROR(Render_Vulkan, "Invalid GPU address for shader 0x{:016x}", shader_addr); |
| 776 | last_valid_shaders = false; | ||
| 758 | return false; | 777 | return false; |
| 759 | } | 778 | } |
| 760 | const ShaderInfo* shader_info{TryGet(*cpu_shader_addr)}; | 779 | const ShaderInfo* shader_info{TryGet(*cpu_shader_addr)}; |
| @@ -766,6 +785,7 @@ bool PipelineCache::RefreshStages() { | |||
| 766 | shader_infos[index] = shader_info; | 785 | shader_infos[index] = shader_info; |
| 767 | graphics_key.unique_hashes[index] = shader_info->unique_hash; | 786 | graphics_key.unique_hashes[index] = shader_info->unique_hash; |
| 768 | } | 787 | } |
| 788 | last_valid_shaders = true; | ||
| 769 | return true; | 789 | return true; |
| 770 | } | 790 | } |
| 771 | 791 | ||
| @@ -832,8 +852,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | |||
| 832 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; | 852 | Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; |
| 833 | return std::make_unique<GraphicsPipeline>( | 853 | return std::make_unique<GraphicsPipeline>( |
| 834 | maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, device, descriptor_pool, | 854 | maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, device, descriptor_pool, |
| 835 | update_descriptor_queue, thread_worker, render_pass_cache, key.state, std::move(modules), | 855 | update_descriptor_queue, thread_worker, render_pass_cache, key, std::move(modules), infos); |
| 836 | infos); | ||
| 837 | } | 856 | } |
| 838 | 857 | ||
| 839 | std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() { | 858 | std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() { |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index e12e4422f..ad569acc4 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -58,26 +58,6 @@ static_assert(std::has_unique_object_representations_v<ComputePipelineCacheKey>) | |||
| 58 | static_assert(std::is_trivially_copyable_v<ComputePipelineCacheKey>); | 58 | static_assert(std::is_trivially_copyable_v<ComputePipelineCacheKey>); |
| 59 | static_assert(std::is_trivially_constructible_v<ComputePipelineCacheKey>); | 59 | static_assert(std::is_trivially_constructible_v<ComputePipelineCacheKey>); |
| 60 | 60 | ||
| 61 | struct GraphicsPipelineCacheKey { | ||
| 62 | std::array<u128, 6> unique_hashes; | ||
| 63 | FixedPipelineState state; | ||
| 64 | |||
| 65 | size_t Hash() const noexcept; | ||
| 66 | |||
| 67 | bool operator==(const GraphicsPipelineCacheKey& rhs) const noexcept; | ||
| 68 | |||
| 69 | bool operator!=(const GraphicsPipelineCacheKey& rhs) const noexcept { | ||
| 70 | return !operator==(rhs); | ||
| 71 | } | ||
| 72 | |||
| 73 | size_t Size() const noexcept { | ||
| 74 | return sizeof(unique_hashes) + state.Size(); | ||
| 75 | } | ||
| 76 | }; | ||
| 77 | static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>); | ||
| 78 | static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>); | ||
| 79 | static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>); | ||
| 80 | |||
| 81 | } // namespace Vulkan | 61 | } // namespace Vulkan |
| 82 | 62 | ||
| 83 | namespace std { | 63 | namespace std { |
| @@ -89,13 +69,6 @@ struct hash<Vulkan::ComputePipelineCacheKey> { | |||
| 89 | } | 69 | } |
| 90 | }; | 70 | }; |
| 91 | 71 | ||
| 92 | template <> | ||
| 93 | struct hash<Vulkan::GraphicsPipelineCacheKey> { | ||
| 94 | size_t operator()(const Vulkan::GraphicsPipelineCacheKey& k) const noexcept { | ||
| 95 | return k.Hash(); | ||
| 96 | } | ||
| 97 | }; | ||
| 98 | |||
| 99 | } // namespace std | 72 | } // namespace std |
| 100 | 73 | ||
| 101 | namespace Vulkan { | 74 | namespace Vulkan { |
| @@ -181,7 +154,10 @@ private: | |||
| 181 | TextureCache& texture_cache; | 154 | TextureCache& texture_cache; |
| 182 | 155 | ||
| 183 | GraphicsPipelineCacheKey graphics_key{}; | 156 | GraphicsPipelineCacheKey graphics_key{}; |
| 157 | GraphicsPipeline* current_pipeline{}; | ||
| 158 | |||
| 184 | std::array<const ShaderInfo*, 6> shader_infos{}; | 159 | std::array<const ShaderInfo*, 6> shader_infos{}; |
| 160 | bool last_valid_shaders{}; | ||
| 185 | 161 | ||
| 186 | std::unordered_map<ComputePipelineCacheKey, std::unique_ptr<ComputePipeline>> compute_cache; | 162 | std::unordered_map<ComputePipelineCacheKey, std::unique_ptr<ComputePipeline>> compute_cache; |
| 187 | std::unordered_map<GraphicsPipelineCacheKey, std::unique_ptr<GraphicsPipeline>> graphics_cache; | 163 | std::unordered_map<GraphicsPipelineCacheKey, std::unique_ptr<GraphicsPipeline>> graphics_cache; |