diff options
| author | 2021-01-10 22:09:56 -0700 | |
|---|---|---|
| committer | 2021-01-10 22:09:56 -0700 | |
| commit | 7a3c884e39fccfbb498b855080bffabc9ce2e7f1 (patch) | |
| tree | 5056f9406dec188439cb0deb87603498243a9412 /src/video_core/renderer_vulkan | |
| parent | More forgetting... duh (diff) | |
| parent | Merge pull request #5229 from Morph1984/fullscreen-opt (diff) | |
| download | yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.gz yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.xz yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.zip | |
Merge remote-tracking branch 'upstream/master' into int-flags
Diffstat (limited to 'src/video_core/renderer_vulkan')
69 files changed, 3149 insertions, 6552 deletions
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp new file mode 100644 index 000000000..1f6a169ae --- /dev/null +++ b/src/video_core/renderer_vulkan/blit_image.cpp | |||
| @@ -0,0 +1,624 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | |||
| 7 | #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" | ||
| 8 | #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" | ||
| 9 | #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" | ||
| 10 | #include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h" | ||
| 11 | #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" | ||
| 12 | #include "video_core/renderer_vulkan/blit_image.h" | ||
| 13 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 16 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | ||
| 17 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | ||
| 18 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | ||
| 19 | #include "video_core/surface.h" | ||
| 20 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 21 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 22 | |||
| 23 | namespace Vulkan { | ||
| 24 | |||
| 25 | using VideoCommon::ImageViewType; | ||
| 26 | |||
| 27 | namespace { | ||
| 28 | struct PushConstants { | ||
| 29 | std::array<float, 2> tex_scale; | ||
| 30 | std::array<float, 2> tex_offset; | ||
| 31 | }; | ||
| 32 | |||
| 33 | template <u32 binding> | ||
| 34 | inline constexpr VkDescriptorSetLayoutBinding TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING{ | ||
| 35 | .binding = binding, | ||
| 36 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 37 | .descriptorCount = 1, | ||
| 38 | .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 39 | .pImmutableSamplers = nullptr, | ||
| 40 | }; | ||
| 41 | constexpr std::array TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS{ | ||
| 42 | TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<0>, | ||
| 43 | TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<1>, | ||
| 44 | }; | ||
| 45 | constexpr VkDescriptorSetLayoutCreateInfo ONE_TEXTURE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO{ | ||
| 46 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 47 | .pNext = nullptr, | ||
| 48 | .flags = 0, | ||
| 49 | .bindingCount = 1, | ||
| 50 | .pBindings = &TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<0>, | ||
| 51 | }; | ||
| 52 | constexpr VkDescriptorSetLayoutCreateInfo TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO{ | ||
| 53 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 54 | .pNext = nullptr, | ||
| 55 | .flags = 0, | ||
| 56 | .bindingCount = static_cast<u32>(TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.size()), | ||
| 57 | .pBindings = TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.data(), | ||
| 58 | }; | ||
| 59 | constexpr VkPushConstantRange PUSH_CONSTANT_RANGE{ | ||
| 60 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 61 | .offset = 0, | ||
| 62 | .size = sizeof(PushConstants), | ||
| 63 | }; | ||
| 64 | constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO{ | ||
| 65 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 66 | .pNext = nullptr, | ||
| 67 | .flags = 0, | ||
| 68 | .vertexBindingDescriptionCount = 0, | ||
| 69 | .pVertexBindingDescriptions = nullptr, | ||
| 70 | .vertexAttributeDescriptionCount = 0, | ||
| 71 | .pVertexAttributeDescriptions = nullptr, | ||
| 72 | }; | ||
| 73 | constexpr VkPipelineInputAssemblyStateCreateInfo PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO{ | ||
| 74 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 75 | .pNext = nullptr, | ||
| 76 | .flags = 0, | ||
| 77 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, | ||
| 78 | .primitiveRestartEnable = VK_FALSE, | ||
| 79 | }; | ||
| 80 | constexpr VkPipelineViewportStateCreateInfo PIPELINE_VIEWPORT_STATE_CREATE_INFO{ | ||
| 81 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 82 | .pNext = nullptr, | ||
| 83 | .flags = 0, | ||
| 84 | .viewportCount = 1, | ||
| 85 | .pViewports = nullptr, | ||
| 86 | .scissorCount = 1, | ||
| 87 | .pScissors = nullptr, | ||
| 88 | }; | ||
| 89 | constexpr VkPipelineRasterizationStateCreateInfo PIPELINE_RASTERIZATION_STATE_CREATE_INFO{ | ||
| 90 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 91 | .pNext = nullptr, | ||
| 92 | .flags = 0, | ||
| 93 | .depthClampEnable = VK_FALSE, | ||
| 94 | .rasterizerDiscardEnable = VK_FALSE, | ||
| 95 | .polygonMode = VK_POLYGON_MODE_FILL, | ||
| 96 | .cullMode = VK_CULL_MODE_BACK_BIT, | ||
| 97 | .frontFace = VK_FRONT_FACE_CLOCKWISE, | ||
| 98 | .depthBiasEnable = VK_FALSE, | ||
| 99 | .depthBiasConstantFactor = 0.0f, | ||
| 100 | .depthBiasClamp = 0.0f, | ||
| 101 | .depthBiasSlopeFactor = 0.0f, | ||
| 102 | .lineWidth = 1.0f, | ||
| 103 | }; | ||
| 104 | constexpr VkPipelineMultisampleStateCreateInfo PIPELINE_MULTISAMPLE_STATE_CREATE_INFO{ | ||
| 105 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 106 | .pNext = nullptr, | ||
| 107 | .flags = 0, | ||
| 108 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | ||
| 109 | .sampleShadingEnable = VK_FALSE, | ||
| 110 | .minSampleShading = 0.0f, | ||
| 111 | .pSampleMask = nullptr, | ||
| 112 | .alphaToCoverageEnable = VK_FALSE, | ||
| 113 | .alphaToOneEnable = VK_FALSE, | ||
| 114 | }; | ||
| 115 | constexpr std::array DYNAMIC_STATES{ | ||
| 116 | VK_DYNAMIC_STATE_VIEWPORT, | ||
| 117 | VK_DYNAMIC_STATE_SCISSOR, | ||
| 118 | }; | ||
| 119 | constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{ | ||
| 120 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 121 | .pNext = nullptr, | ||
| 122 | .flags = 0, | ||
| 123 | .dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()), | ||
| 124 | .pDynamicStates = DYNAMIC_STATES.data(), | ||
| 125 | }; | ||
| 126 | constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{ | ||
| 127 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||
| 128 | .pNext = nullptr, | ||
| 129 | .flags = 0, | ||
| 130 | .logicOpEnable = VK_FALSE, | ||
| 131 | .logicOp = VK_LOGIC_OP_CLEAR, | ||
| 132 | .attachmentCount = 0, | ||
| 133 | .pAttachments = nullptr, | ||
| 134 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | ||
| 135 | }; | ||
| 136 | constexpr VkPipelineColorBlendAttachmentState PIPELINE_COLOR_BLEND_ATTACHMENT_STATE{ | ||
| 137 | .blendEnable = VK_FALSE, | ||
| 138 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 139 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 140 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 141 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 142 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 143 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 144 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 145 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 146 | }; | ||
| 147 | constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO{ | ||
| 148 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||
| 149 | .pNext = nullptr, | ||
| 150 | .flags = 0, | ||
| 151 | .logicOpEnable = VK_FALSE, | ||
| 152 | .logicOp = VK_LOGIC_OP_CLEAR, | ||
| 153 | .attachmentCount = 1, | ||
| 154 | .pAttachments = &PIPELINE_COLOR_BLEND_ATTACHMENT_STATE, | ||
| 155 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | ||
| 156 | }; | ||
| 157 | constexpr VkPipelineDepthStencilStateCreateInfo PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO{ | ||
| 158 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | ||
| 159 | .pNext = nullptr, | ||
| 160 | .flags = 0, | ||
| 161 | .depthTestEnable = VK_TRUE, | ||
| 162 | .depthWriteEnable = VK_TRUE, | ||
| 163 | .depthCompareOp = VK_COMPARE_OP_ALWAYS, | ||
| 164 | .depthBoundsTestEnable = VK_FALSE, | ||
| 165 | .stencilTestEnable = VK_FALSE, | ||
| 166 | .front = VkStencilOpState{}, | ||
| 167 | .back = VkStencilOpState{}, | ||
| 168 | .minDepthBounds = 0.0f, | ||
| 169 | .maxDepthBounds = 0.0f, | ||
| 170 | }; | ||
| 171 | |||
| 172 | template <VkFilter filter> | ||
| 173 | inline constexpr VkSamplerCreateInfo SAMPLER_CREATE_INFO{ | ||
| 174 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 175 | .pNext = nullptr, | ||
| 176 | .flags = 0, | ||
| 177 | .magFilter = filter, | ||
| 178 | .minFilter = filter, | ||
| 179 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 180 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 181 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 182 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 183 | .mipLodBias = 0.0f, | ||
| 184 | .anisotropyEnable = VK_FALSE, | ||
| 185 | .maxAnisotropy = 0.0f, | ||
| 186 | .compareEnable = VK_FALSE, | ||
| 187 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 188 | .minLod = 0.0f, | ||
| 189 | .maxLod = 0.0f, | ||
| 190 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, | ||
| 191 | .unnormalizedCoordinates = VK_TRUE, | ||
| 192 | }; | ||
| 193 | |||
| 194 | constexpr VkPipelineLayoutCreateInfo PipelineLayoutCreateInfo( | ||
| 195 | const VkDescriptorSetLayout* set_layout) { | ||
| 196 | return VkPipelineLayoutCreateInfo{ | ||
| 197 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 198 | .pNext = nullptr, | ||
| 199 | .flags = 0, | ||
| 200 | .setLayoutCount = 1, | ||
| 201 | .pSetLayouts = set_layout, | ||
| 202 | .pushConstantRangeCount = 1, | ||
| 203 | .pPushConstantRanges = &PUSH_CONSTANT_RANGE, | ||
| 204 | }; | ||
| 205 | } | ||
| 206 | |||
| 207 | constexpr VkPipelineShaderStageCreateInfo PipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, | ||
| 208 | VkShaderModule shader) { | ||
| 209 | return VkPipelineShaderStageCreateInfo{ | ||
| 210 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 211 | .pNext = nullptr, | ||
| 212 | .flags = 0, | ||
| 213 | .stage = stage, | ||
| 214 | .module = shader, | ||
| 215 | .pName = "main", | ||
| 216 | .pSpecializationInfo = nullptr, | ||
| 217 | }; | ||
| 218 | } | ||
| 219 | |||
| 220 | constexpr std::array<VkPipelineShaderStageCreateInfo, 2> MakeStages( | ||
| 221 | VkShaderModule vertex_shader, VkShaderModule fragment_shader) { | ||
| 222 | return std::array{ | ||
| 223 | PipelineShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, vertex_shader), | ||
| 224 | PipelineShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, fragment_shader), | ||
| 225 | }; | ||
| 226 | } | ||
| 227 | |||
| 228 | void UpdateOneTextureDescriptorSet(const Device& device, VkDescriptorSet descriptor_set, | ||
| 229 | VkSampler sampler, VkImageView image_view) { | ||
| 230 | const VkDescriptorImageInfo image_info{ | ||
| 231 | .sampler = sampler, | ||
| 232 | .imageView = image_view, | ||
| 233 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 234 | }; | ||
| 235 | const VkWriteDescriptorSet write_descriptor_set{ | ||
| 236 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 237 | .pNext = nullptr, | ||
| 238 | .dstSet = descriptor_set, | ||
| 239 | .dstBinding = 0, | ||
| 240 | .dstArrayElement = 0, | ||
| 241 | .descriptorCount = 1, | ||
| 242 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 243 | .pImageInfo = &image_info, | ||
| 244 | .pBufferInfo = nullptr, | ||
| 245 | .pTexelBufferView = nullptr, | ||
| 246 | }; | ||
| 247 | device.GetLogical().UpdateDescriptorSets(write_descriptor_set, nullptr); | ||
| 248 | } | ||
| 249 | |||
| 250 | void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descriptor_set, | ||
| 251 | VkSampler sampler, VkImageView image_view_0, | ||
| 252 | VkImageView image_view_1) { | ||
| 253 | const VkDescriptorImageInfo image_info_0{ | ||
| 254 | .sampler = sampler, | ||
| 255 | .imageView = image_view_0, | ||
| 256 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 257 | }; | ||
| 258 | const VkDescriptorImageInfo image_info_1{ | ||
| 259 | .sampler = sampler, | ||
| 260 | .imageView = image_view_1, | ||
| 261 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 262 | }; | ||
| 263 | const std::array write_descriptor_sets{ | ||
| 264 | VkWriteDescriptorSet{ | ||
| 265 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 266 | .pNext = nullptr, | ||
| 267 | .dstSet = descriptor_set, | ||
| 268 | .dstBinding = 0, | ||
| 269 | .dstArrayElement = 0, | ||
| 270 | .descriptorCount = 1, | ||
| 271 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 272 | .pImageInfo = &image_info_0, | ||
| 273 | .pBufferInfo = nullptr, | ||
| 274 | .pTexelBufferView = nullptr, | ||
| 275 | }, | ||
| 276 | VkWriteDescriptorSet{ | ||
| 277 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 278 | .pNext = nullptr, | ||
| 279 | .dstSet = descriptor_set, | ||
| 280 | .dstBinding = 1, | ||
| 281 | .dstArrayElement = 0, | ||
| 282 | .descriptorCount = 1, | ||
| 283 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 284 | .pImageInfo = &image_info_1, | ||
| 285 | .pBufferInfo = nullptr, | ||
| 286 | .pTexelBufferView = nullptr, | ||
| 287 | }, | ||
| 288 | }; | ||
| 289 | device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); | ||
| 290 | } | ||
| 291 | |||
| 292 | void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, | ||
| 293 | const std::array<Offset2D, 2>& dst_region, | ||
| 294 | const std::array<Offset2D, 2>& src_region) { | ||
| 295 | const VkOffset2D offset{ | ||
| 296 | .x = std::min(dst_region[0].x, dst_region[1].x), | ||
| 297 | .y = std::min(dst_region[0].y, dst_region[1].y), | ||
| 298 | }; | ||
| 299 | const VkExtent2D extent{ | ||
| 300 | .width = static_cast<u32>(std::abs(dst_region[1].x - dst_region[0].x)), | ||
| 301 | .height = static_cast<u32>(std::abs(dst_region[1].y - dst_region[0].y)), | ||
| 302 | }; | ||
| 303 | const VkViewport viewport{ | ||
| 304 | .x = static_cast<float>(offset.x), | ||
| 305 | .y = static_cast<float>(offset.y), | ||
| 306 | .width = static_cast<float>(extent.width), | ||
| 307 | .height = static_cast<float>(extent.height), | ||
| 308 | .minDepth = 0.0f, | ||
| 309 | .maxDepth = 1.0f, | ||
| 310 | }; | ||
| 311 | // TODO: Support scissored blits | ||
| 312 | const VkRect2D scissor{ | ||
| 313 | .offset = offset, | ||
| 314 | .extent = extent, | ||
| 315 | }; | ||
| 316 | const float scale_x = static_cast<float>(src_region[1].x - src_region[0].x); | ||
| 317 | const float scale_y = static_cast<float>(src_region[1].y - src_region[0].y); | ||
| 318 | const PushConstants push_constants{ | ||
| 319 | .tex_scale = {scale_x, scale_y}, | ||
| 320 | .tex_offset = {static_cast<float>(src_region[0].x), static_cast<float>(src_region[0].y)}, | ||
| 321 | }; | ||
| 322 | cmdbuf.SetViewport(0, viewport); | ||
| 323 | cmdbuf.SetScissor(0, scissor); | ||
| 324 | cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); | ||
| 325 | } | ||
| 326 | |||
| 327 | } // Anonymous namespace | ||
| 328 | |||
| 329 | BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, | ||
| 330 | StateTracker& state_tracker_, VKDescriptorPool& descriptor_pool) | ||
| 331 | : device{device_}, scheduler{scheduler_}, state_tracker{state_tracker_}, | ||
| 332 | one_texture_set_layout(device.GetLogical().CreateDescriptorSetLayout( | ||
| 333 | ONE_TEXTURE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)), | ||
| 334 | two_textures_set_layout(device.GetLogical().CreateDescriptorSetLayout( | ||
| 335 | TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)), | ||
| 336 | one_texture_descriptor_allocator(descriptor_pool, *one_texture_set_layout), | ||
| 337 | two_textures_descriptor_allocator(descriptor_pool, *two_textures_set_layout), | ||
| 338 | one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout( | ||
| 339 | PipelineLayoutCreateInfo(one_texture_set_layout.address()))), | ||
| 340 | two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout( | ||
| 341 | PipelineLayoutCreateInfo(two_textures_set_layout.address()))), | ||
| 342 | full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), | ||
| 343 | blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), | ||
| 344 | convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), | ||
| 345 | convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), | ||
| 346 | linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)), | ||
| 347 | nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) { | ||
| 348 | if (device.IsExtShaderStencilExportSupported()) { | ||
| 349 | blit_depth_stencil_frag = BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | BlitImageHelper::~BlitImageHelper() = default; | ||
| 354 | |||
| 355 | void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | ||
| 356 | const std::array<Offset2D, 2>& dst_region, | ||
| 357 | const std::array<Offset2D, 2>& src_region, | ||
| 358 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 359 | Tegra::Engines::Fermi2D::Operation operation) { | ||
| 360 | const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear; | ||
| 361 | const BlitImagePipelineKey key{ | ||
| 362 | .renderpass = dst_framebuffer->RenderPass(), | ||
| 363 | .operation = operation, | ||
| 364 | }; | ||
| 365 | const VkPipelineLayout layout = *one_texture_pipeline_layout; | ||
| 366 | const VkImageView src_view = src_image_view.Handle(ImageViewType::e2D); | ||
| 367 | const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler; | ||
| 368 | const VkPipeline pipeline = FindOrEmplacePipeline(key); | ||
| 369 | const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); | ||
| 370 | scheduler.RequestRenderpass(dst_framebuffer); | ||
| 371 | scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_view, descriptor_set, | ||
| 372 | &device = device](vk::CommandBuffer cmdbuf) { | ||
| 373 | // TODO: Barriers | ||
| 374 | UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view); | ||
| 375 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 376 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | ||
| 377 | nullptr); | ||
| 378 | BindBlitState(cmdbuf, layout, dst_region, src_region); | ||
| 379 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 380 | }); | ||
| 381 | scheduler.InvalidateState(); | ||
| 382 | } | ||
| 383 | |||
| 384 | void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, | ||
| 385 | VkImageView src_depth_view, VkImageView src_stencil_view, | ||
| 386 | const std::array<Offset2D, 2>& dst_region, | ||
| 387 | const std::array<Offset2D, 2>& src_region, | ||
| 388 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 389 | Tegra::Engines::Fermi2D::Operation operation) { | ||
| 390 | ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); | ||
| 391 | ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy); | ||
| 392 | |||
| 393 | const VkPipelineLayout layout = *two_textures_pipeline_layout; | ||
| 394 | const VkSampler sampler = *nearest_sampler; | ||
| 395 | const VkPipeline pipeline = BlitDepthStencilPipeline(dst_framebuffer->RenderPass()); | ||
| 396 | const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit(); | ||
| 397 | scheduler.RequestRenderpass(dst_framebuffer); | ||
| 398 | scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_depth_view, | ||
| 399 | src_stencil_view, descriptor_set, | ||
| 400 | &device = device](vk::CommandBuffer cmdbuf) { | ||
| 401 | // TODO: Barriers | ||
| 402 | UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view, | ||
| 403 | src_stencil_view); | ||
| 404 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 405 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | ||
| 406 | nullptr); | ||
| 407 | BindBlitState(cmdbuf, layout, dst_region, src_region); | ||
| 408 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 409 | }); | ||
| 410 | scheduler.InvalidateState(); | ||
| 411 | } | ||
| 412 | |||
| 413 | void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer, | ||
| 414 | const ImageView& src_image_view) { | ||
| 415 | ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass()); | ||
| 416 | Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view); | ||
| 417 | } | ||
| 418 | |||
| 419 | void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer, | ||
| 420 | const ImageView& src_image_view) { | ||
| 421 | |||
| 422 | ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass()); | ||
| 423 | Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view); | ||
| 424 | } | ||
| 425 | |||
| 426 | void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer, | ||
| 427 | const ImageView& src_image_view) { | ||
| 428 | ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass()); | ||
| 429 | Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view); | ||
| 430 | } | ||
| 431 | |||
| 432 | void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer, | ||
| 433 | const ImageView& src_image_view) { | ||
| 434 | ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass()); | ||
| 435 | Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view); | ||
| 436 | } | ||
| 437 | |||
| 438 | void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | ||
| 439 | const ImageView& src_image_view) { | ||
| 440 | const VkPipelineLayout layout = *one_texture_pipeline_layout; | ||
| 441 | const VkImageView src_view = src_image_view.Handle(ImageViewType::e2D); | ||
| 442 | const VkSampler sampler = *nearest_sampler; | ||
| 443 | const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); | ||
| 444 | const VkExtent2D extent{ | ||
| 445 | .width = src_image_view.size.width, | ||
| 446 | .height = src_image_view.size.height, | ||
| 447 | }; | ||
| 448 | scheduler.RequestRenderpass(dst_framebuffer); | ||
| 449 | scheduler.Record([pipeline, layout, sampler, src_view, descriptor_set, extent, | ||
| 450 | &device = device](vk::CommandBuffer cmdbuf) { | ||
| 451 | const VkOffset2D offset{ | ||
| 452 | .x = 0, | ||
| 453 | .y = 0, | ||
| 454 | }; | ||
| 455 | const VkViewport viewport{ | ||
| 456 | .x = 0.0f, | ||
| 457 | .y = 0.0f, | ||
| 458 | .width = static_cast<float>(extent.width), | ||
| 459 | .height = static_cast<float>(extent.height), | ||
| 460 | .minDepth = 0.0f, | ||
| 461 | .maxDepth = 0.0f, | ||
| 462 | }; | ||
| 463 | const VkRect2D scissor{ | ||
| 464 | .offset = offset, | ||
| 465 | .extent = extent, | ||
| 466 | }; | ||
| 467 | const PushConstants push_constants{ | ||
| 468 | .tex_scale = {viewport.width, viewport.height}, | ||
| 469 | .tex_offset = {0.0f, 0.0f}, | ||
| 470 | }; | ||
| 471 | UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view); | ||
| 472 | |||
| 473 | // TODO: Barriers | ||
| 474 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 475 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | ||
| 476 | nullptr); | ||
| 477 | cmdbuf.SetViewport(0, viewport); | ||
| 478 | cmdbuf.SetScissor(0, scissor); | ||
| 479 | cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); | ||
| 480 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 481 | }); | ||
| 482 | scheduler.InvalidateState(); | ||
| 483 | } | ||
| 484 | |||
| 485 | VkPipeline BlitImageHelper::FindOrEmplacePipeline(const BlitImagePipelineKey& key) { | ||
| 486 | const auto it = std::ranges::find(blit_color_keys, key); | ||
| 487 | if (it != blit_color_keys.end()) { | ||
| 488 | return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)]; | ||
| 489 | } | ||
| 490 | blit_color_keys.push_back(key); | ||
| 491 | |||
| 492 | const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag); | ||
| 493 | const VkPipelineColorBlendAttachmentState blend_attachment{ | ||
| 494 | .blendEnable = VK_FALSE, | ||
| 495 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 496 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 497 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 498 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 499 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 500 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 501 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 502 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 503 | }; | ||
| 504 | // TODO: programmable blending | ||
| 505 | const VkPipelineColorBlendStateCreateInfo color_blend_create_info{ | ||
| 506 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||
| 507 | .pNext = nullptr, | ||
| 508 | .flags = 0, | ||
| 509 | .logicOpEnable = VK_FALSE, | ||
| 510 | .logicOp = VK_LOGIC_OP_CLEAR, | ||
| 511 | .attachmentCount = 1, | ||
| 512 | .pAttachments = &blend_attachment, | ||
| 513 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | ||
| 514 | }; | ||
| 515 | blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ | ||
| 516 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 517 | .pNext = nullptr, | ||
| 518 | .flags = 0, | ||
| 519 | .stageCount = static_cast<u32>(stages.size()), | ||
| 520 | .pStages = stages.data(), | ||
| 521 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 522 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 523 | .pTessellationState = nullptr, | ||
| 524 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 525 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 526 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 527 | .pDepthStencilState = nullptr, | ||
| 528 | .pColorBlendState = &color_blend_create_info, | ||
| 529 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 530 | .layout = *one_texture_pipeline_layout, | ||
| 531 | .renderPass = key.renderpass, | ||
| 532 | .subpass = 0, | ||
| 533 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 534 | .basePipelineIndex = 0, | ||
| 535 | })); | ||
| 536 | return *blit_color_pipelines.back(); | ||
| 537 | } | ||
| 538 | |||
| 539 | VkPipeline BlitImageHelper::BlitDepthStencilPipeline(VkRenderPass renderpass) { | ||
| 540 | if (blit_depth_stencil_pipeline) { | ||
| 541 | return *blit_depth_stencil_pipeline; | ||
| 542 | } | ||
| 543 | const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag); | ||
| 544 | blit_depth_stencil_pipeline = device.GetLogical().CreateGraphicsPipeline({ | ||
| 545 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 546 | .pNext = nullptr, | ||
| 547 | .flags = 0, | ||
| 548 | .stageCount = static_cast<u32>(stages.size()), | ||
| 549 | .pStages = stages.data(), | ||
| 550 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 551 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 552 | .pTessellationState = nullptr, | ||
| 553 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 554 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 555 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 556 | .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | ||
| 557 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, | ||
| 558 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 559 | .layout = *two_textures_pipeline_layout, | ||
| 560 | .renderPass = renderpass, | ||
| 561 | .subpass = 0, | ||
| 562 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 563 | .basePipelineIndex = 0, | ||
| 564 | }); | ||
| 565 | return *blit_depth_stencil_pipeline; | ||
| 566 | } | ||
| 567 | |||
| 568 | void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) { | ||
| 569 | if (pipeline) { | ||
| 570 | return; | ||
| 571 | } | ||
| 572 | const std::array stages = MakeStages(*full_screen_vert, *convert_depth_to_float_frag); | ||
| 573 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | ||
| 574 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 575 | .pNext = nullptr, | ||
| 576 | .flags = 0, | ||
| 577 | .stageCount = static_cast<u32>(stages.size()), | ||
| 578 | .pStages = stages.data(), | ||
| 579 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 580 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 581 | .pTessellationState = nullptr, | ||
| 582 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 583 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 584 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 585 | .pDepthStencilState = nullptr, | ||
| 586 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, | ||
| 587 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 588 | .layout = *one_texture_pipeline_layout, | ||
| 589 | .renderPass = renderpass, | ||
| 590 | .subpass = 0, | ||
| 591 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 592 | .basePipelineIndex = 0, | ||
| 593 | }); | ||
| 594 | } | ||
| 595 | |||
| 596 | void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) { | ||
| 597 | if (pipeline) { | ||
| 598 | return; | ||
| 599 | } | ||
| 600 | const std::array stages = MakeStages(*full_screen_vert, *convert_float_to_depth_frag); | ||
| 601 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | ||
| 602 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 603 | .pNext = nullptr, | ||
| 604 | .flags = 0, | ||
| 605 | .stageCount = static_cast<u32>(stages.size()), | ||
| 606 | .pStages = stages.data(), | ||
| 607 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 608 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 609 | .pTessellationState = nullptr, | ||
| 610 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 611 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 612 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 613 | .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | ||
| 614 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, | ||
| 615 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 616 | .layout = *one_texture_pipeline_layout, | ||
| 617 | .renderPass = renderpass, | ||
| 618 | .subpass = 0, | ||
| 619 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 620 | .basePipelineIndex = 0, | ||
| 621 | }); | ||
| 622 | } | ||
| 623 | |||
| 624 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h new file mode 100644 index 000000000..43fd3d737 --- /dev/null +++ b/src/video_core/renderer_vulkan/blit_image.h | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <compare> | ||
| 8 | |||
| 9 | #include "video_core/engines/fermi_2d.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | ||
| 11 | #include "video_core/texture_cache/types.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | using VideoCommon::Offset2D; | ||
| 17 | |||
| 18 | class Device; | ||
| 19 | class Framebuffer; | ||
| 20 | class ImageView; | ||
| 21 | class StateTracker; | ||
| 22 | class VKScheduler; | ||
| 23 | |||
| 24 | struct BlitImagePipelineKey { | ||
| 25 | constexpr auto operator<=>(const BlitImagePipelineKey&) const noexcept = default; | ||
| 26 | |||
| 27 | VkRenderPass renderpass; | ||
| 28 | Tegra::Engines::Fermi2D::Operation operation; | ||
| 29 | }; | ||
| 30 | |||
| 31 | class BlitImageHelper { | ||
| 32 | public: | ||
| 33 | explicit BlitImageHelper(const Device& device, VKScheduler& scheduler, | ||
| 34 | StateTracker& state_tracker, VKDescriptorPool& descriptor_pool); | ||
| 35 | ~BlitImageHelper(); | ||
| 36 | |||
| 37 | void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | ||
| 38 | const std::array<Offset2D, 2>& dst_region, | ||
| 39 | const std::array<Offset2D, 2>& src_region, | ||
| 40 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 41 | Tegra::Engines::Fermi2D::Operation operation); | ||
| 42 | |||
| 43 | void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, | ||
| 44 | VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region, | ||
| 45 | const std::array<Offset2D, 2>& src_region, | ||
| 46 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 47 | Tegra::Engines::Fermi2D::Operation operation); | ||
| 48 | |||
| 49 | void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | ||
| 50 | |||
| 51 | void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | ||
| 52 | |||
| 53 | void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | ||
| 54 | |||
| 55 | void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | ||
| 56 | |||
| 57 | private: | ||
| 58 | void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | ||
| 59 | const ImageView& src_image_view); | ||
| 60 | |||
| 61 | [[nodiscard]] VkPipeline FindOrEmplacePipeline(const BlitImagePipelineKey& key); | ||
| 62 | |||
| 63 | [[nodiscard]] VkPipeline BlitDepthStencilPipeline(VkRenderPass renderpass); | ||
| 64 | |||
| 65 | void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); | ||
| 66 | |||
| 67 | void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); | ||
| 68 | |||
| 69 | const Device& device; | ||
| 70 | VKScheduler& scheduler; | ||
| 71 | StateTracker& state_tracker; | ||
| 72 | |||
| 73 | vk::DescriptorSetLayout one_texture_set_layout; | ||
| 74 | vk::DescriptorSetLayout two_textures_set_layout; | ||
| 75 | DescriptorAllocator one_texture_descriptor_allocator; | ||
| 76 | DescriptorAllocator two_textures_descriptor_allocator; | ||
| 77 | vk::PipelineLayout one_texture_pipeline_layout; | ||
| 78 | vk::PipelineLayout two_textures_pipeline_layout; | ||
| 79 | vk::ShaderModule full_screen_vert; | ||
| 80 | vk::ShaderModule blit_color_to_color_frag; | ||
| 81 | vk::ShaderModule blit_depth_stencil_frag; | ||
| 82 | vk::ShaderModule convert_depth_to_float_frag; | ||
| 83 | vk::ShaderModule convert_float_to_depth_frag; | ||
| 84 | vk::Sampler linear_sampler; | ||
| 85 | vk::Sampler nearest_sampler; | ||
| 86 | |||
| 87 | std::vector<BlitImagePipelineKey> blit_color_keys; | ||
| 88 | std::vector<vk::Pipeline> blit_color_pipelines; | ||
| 89 | vk::Pipeline blit_depth_stencil_pipeline; | ||
| 90 | vk::Pipeline convert_d32_to_r32_pipeline; | ||
| 91 | vk::Pipeline convert_r32_to_d32_pipeline; | ||
| 92 | vk::Pipeline convert_d16_to_r16_pipeline; | ||
| 93 | vk::Pipeline convert_r16_to_d16_pipeline; | ||
| 94 | }; | ||
| 95 | |||
| 96 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 81a39a3b8..5be6dabd9 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include <boost/functional/hash.hpp> | 9 | #include <boost/functional/hash.hpp> |
| 10 | 10 | ||
| 11 | #include "common/bit_cast.h" | ||
| 11 | #include "common/cityhash.h" | 12 | #include "common/cityhash.h" |
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 13 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 14 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| @@ -45,7 +46,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta | |||
| 45 | regs.polygon_offset_fill_enable}; | 46 | regs.polygon_offset_fill_enable}; |
| 46 | const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); | 47 | const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); |
| 47 | 48 | ||
| 48 | raw = 0; | 49 | raw1 = 0; |
| 49 | primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); | 50 | primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); |
| 50 | depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); | 51 | depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); |
| 51 | depth_clamp_disabled.Assign(regs.view_volume_clip_control.depth_clamp_disabled.Value()); | 52 | depth_clamp_disabled.Assign(regs.view_volume_clip_control.depth_clamp_disabled.Value()); |
| @@ -58,15 +59,24 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta | |||
| 58 | logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); | 59 | logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); |
| 59 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); | 60 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); |
| 60 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); | 61 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); |
| 62 | topology.Assign(regs.draw.topology); | ||
| 63 | msaa_mode.Assign(regs.multisample_mode); | ||
| 64 | |||
| 65 | raw2 = 0; | ||
| 66 | const auto test_func = | ||
| 67 | regs.alpha_test_enabled == 1 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always; | ||
| 68 | alpha_test_func.Assign(PackComparisonOp(test_func)); | ||
| 69 | early_z.Assign(regs.force_early_fragment_tests != 0 ? 1 : 0); | ||
| 61 | 70 | ||
| 62 | std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast | 71 | alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref); |
| 72 | point_size = Common::BitCast<u32>(regs.point_size); | ||
| 63 | 73 | ||
| 64 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 74 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 65 | binding_divisors[index] = | 75 | binding_divisors[index] = |
| 66 | regs.instanced_arrays.IsInstancingEnabled(index) ? regs.vertex_array[index].divisor : 0; | 76 | regs.instanced_arrays.IsInstancingEnabled(index) ? regs.vertex_array[index].divisor : 0; |
| 67 | } | 77 | } |
| 68 | 78 | ||
| 69 | for (std::size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { | 79 | for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { |
| 70 | const auto& input = regs.vertex_attrib_format[index]; | 80 | const auto& input = regs.vertex_attrib_format[index]; |
| 71 | auto& attribute = attributes[index]; | 81 | auto& attribute = attributes[index]; |
| 72 | attribute.raw = 0; | 82 | attribute.raw = 0; |
| @@ -75,6 +85,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta | |||
| 75 | attribute.offset.Assign(input.offset); | 85 | attribute.offset.Assign(input.offset); |
| 76 | attribute.type.Assign(static_cast<u32>(input.type.Value())); | 86 | attribute.type.Assign(static_cast<u32>(input.type.Value())); |
| 77 | attribute.size.Assign(static_cast<u32>(input.size.Value())); | 87 | attribute.size.Assign(static_cast<u32>(input.size.Value())); |
| 88 | attribute.binding_index_enabled.Assign(regs.vertex_array[index].IsEnabled() ? 1 : 0); | ||
| 78 | } | 89 | } |
| 79 | 90 | ||
| 80 | for (std::size_t index = 0; index < std::size(attachments); ++index) { | 91 | for (std::size_t index = 0; index < std::size(attachments); ++index) { |
| @@ -131,7 +142,6 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size | |||
| 131 | } | 142 | } |
| 132 | 143 | ||
| 133 | void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { | 144 | void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { |
| 134 | const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); | ||
| 135 | u32 packed_front_face = PackFrontFace(regs.front_face); | 145 | u32 packed_front_face = PackFrontFace(regs.front_face); |
| 136 | if (regs.screen_y_control.triangle_rast_flip != 0) { | 146 | if (regs.screen_y_control.triangle_rast_flip != 0) { |
| 137 | // Flip front face | 147 | // Flip front face |
| @@ -161,17 +171,11 @@ void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { | |||
| 161 | depth_test_enable.Assign(regs.depth_test_enable); | 171 | depth_test_enable.Assign(regs.depth_test_enable); |
| 162 | front_face.Assign(packed_front_face); | 172 | front_face.Assign(packed_front_face); |
| 163 | depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); | 173 | depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); |
| 164 | topology.Assign(topology_index); | ||
| 165 | cull_face.Assign(PackCullFace(regs.cull_face)); | 174 | cull_face.Assign(PackCullFace(regs.cull_face)); |
| 166 | cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); | 175 | cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); |
| 167 | 176 | std::ranges::transform(regs.vertex_array, vertex_strides.begin(), [](const auto& array) { | |
| 168 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 177 | return static_cast<u16>(array.stride.Value()); |
| 169 | const auto& input = regs.vertex_array[index]; | 178 | }); |
| 170 | VertexBinding& binding = vertex_bindings[index]; | ||
| 171 | binding.raw = 0; | ||
| 172 | binding.enabled.Assign(input.IsEnabled() ? 1 : 0); | ||
| 173 | binding.stride.Assign(static_cast<u16>(input.stride.Value())); | ||
| 174 | } | ||
| 175 | } | 179 | } |
| 176 | 180 | ||
| 177 | std::size_t FixedPipelineState::Hash() const noexcept { | 181 | std::size_t FixedPipelineState::Hash() const noexcept { |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index cdcbb65f5..465a55fdb 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h | |||
| @@ -96,6 +96,8 @@ struct FixedPipelineState { | |||
| 96 | BitField<6, 14, u32> offset; | 96 | BitField<6, 14, u32> offset; |
| 97 | BitField<20, 3, u32> type; | 97 | BitField<20, 3, u32> type; |
| 98 | BitField<23, 6, u32> size; | 98 | BitField<23, 6, u32> size; |
| 99 | // Not really an element of a vertex attribute, but it can be packed here | ||
| 100 | BitField<29, 1, u32> binding_index_enabled; | ||
| 99 | 101 | ||
| 100 | constexpr Maxwell::VertexAttribute::Type Type() const noexcept { | 102 | constexpr Maxwell::VertexAttribute::Type Type() const noexcept { |
| 101 | return static_cast<Maxwell::VertexAttribute::Type>(type.Value()); | 103 | return static_cast<Maxwell::VertexAttribute::Type>(type.Value()); |
| @@ -130,12 +132,6 @@ struct FixedPipelineState { | |||
| 130 | } | 132 | } |
| 131 | }; | 133 | }; |
| 132 | 134 | ||
| 133 | union VertexBinding { | ||
| 134 | u16 raw; | ||
| 135 | BitField<0, 12, u16> stride; | ||
| 136 | BitField<12, 1, u16> enabled; | ||
| 137 | }; | ||
| 138 | |||
| 139 | struct DynamicState { | 135 | struct DynamicState { |
| 140 | union { | 136 | union { |
| 141 | u32 raw1; | 137 | u32 raw1; |
| @@ -150,11 +146,11 @@ struct FixedPipelineState { | |||
| 150 | }; | 146 | }; |
| 151 | union { | 147 | union { |
| 152 | u32 raw2; | 148 | u32 raw2; |
| 153 | BitField<0, 4, u32> topology; | 149 | BitField<0, 2, u32> cull_face; |
| 154 | BitField<4, 2, u32> cull_face; | 150 | BitField<2, 1, u32> cull_enable; |
| 155 | BitField<6, 1, u32> cull_enable; | ||
| 156 | }; | 151 | }; |
| 157 | std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings; | 152 | // Vertex stride is a 12 bits value, we have 4 bits to spare per element |
| 153 | std::array<u16, Maxwell::NumVertexArrays> vertex_strides; | ||
| 158 | 154 | ||
| 159 | void Fill(const Maxwell& regs); | 155 | void Fill(const Maxwell& regs); |
| 160 | 156 | ||
| @@ -169,14 +165,10 @@ struct FixedPipelineState { | |||
| 169 | Maxwell::FrontFace FrontFace() const noexcept { | 165 | Maxwell::FrontFace FrontFace() const noexcept { |
| 170 | return UnpackFrontFace(front_face.Value()); | 166 | return UnpackFrontFace(front_face.Value()); |
| 171 | } | 167 | } |
| 172 | |||
| 173 | constexpr Maxwell::PrimitiveTopology Topology() const noexcept { | ||
| 174 | return static_cast<Maxwell::PrimitiveTopology>(topology.Value()); | ||
| 175 | } | ||
| 176 | }; | 168 | }; |
| 177 | 169 | ||
| 178 | union { | 170 | union { |
| 179 | u32 raw; | 171 | u32 raw1; |
| 180 | BitField<0, 1, u32> no_extended_dynamic_state; | 172 | BitField<0, 1, u32> no_extended_dynamic_state; |
| 181 | BitField<2, 1, u32> primitive_restart_enable; | 173 | BitField<2, 1, u32> primitive_restart_enable; |
| 182 | BitField<3, 1, u32> depth_bias_enable; | 174 | BitField<3, 1, u32> depth_bias_enable; |
| @@ -190,7 +182,16 @@ struct FixedPipelineState { | |||
| 190 | BitField<18, 1, u32> logic_op_enable; | 182 | BitField<18, 1, u32> logic_op_enable; |
| 191 | BitField<19, 4, u32> logic_op; | 183 | BitField<19, 4, u32> logic_op; |
| 192 | BitField<23, 1, u32> rasterize_enable; | 184 | BitField<23, 1, u32> rasterize_enable; |
| 185 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; | ||
| 186 | BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode; | ||
| 187 | }; | ||
| 188 | union { | ||
| 189 | u32 raw2; | ||
| 190 | BitField<0, 3, u32> alpha_test_func; | ||
| 191 | BitField<3, 1, u32> early_z; | ||
| 193 | }; | 192 | }; |
| 193 | |||
| 194 | u32 alpha_test_ref; | ||
| 194 | u32 point_size; | 195 | u32 point_size; |
| 195 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; | 196 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; |
| 196 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; | 197 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index d22de1d81..ca7c2c579 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -9,9 +9,9 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "video_core/engines/maxwell_3d.h" | 10 | #include "video_core/engines/maxwell_3d.h" |
| 11 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 11 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 12 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 13 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 14 | #include "video_core/surface.h" | 12 | #include "video_core/surface.h" |
| 13 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 15 | 15 | ||
| 16 | namespace Vulkan::MaxwellToVK { | 16 | namespace Vulkan::MaxwellToVK { |
| 17 | 17 | ||
| @@ -26,7 +26,7 @@ VkFilter Filter(Tegra::Texture::TextureFilter filter) { | |||
| 26 | case Tegra::Texture::TextureFilter::Linear: | 26 | case Tegra::Texture::TextureFilter::Linear: |
| 27 | return VK_FILTER_LINEAR; | 27 | return VK_FILTER_LINEAR; |
| 28 | } | 28 | } |
| 29 | UNREACHABLE_MSG("Invalid sampler filter={}", static_cast<u32>(filter)); | 29 | UNREACHABLE_MSG("Invalid sampler filter={}", filter); |
| 30 | return {}; | 30 | return {}; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| @@ -43,11 +43,11 @@ VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter | |||
| 43 | case Tegra::Texture::TextureMipmapFilter::Linear: | 43 | case Tegra::Texture::TextureMipmapFilter::Linear: |
| 44 | return VK_SAMPLER_MIPMAP_MODE_LINEAR; | 44 | return VK_SAMPLER_MIPMAP_MODE_LINEAR; |
| 45 | } | 45 | } |
| 46 | UNREACHABLE_MSG("Invalid sampler mipmap mode={}", static_cast<u32>(mipmap_filter)); | 46 | UNREACHABLE_MSG("Invalid sampler mipmap mode={}", mipmap_filter); |
| 47 | return {}; | 47 | return {}; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | VkSamplerAddressMode WrapMode(const VKDevice& device, Tegra::Texture::WrapMode wrap_mode, | 50 | VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wrap_mode, |
| 51 | Tegra::Texture::TextureFilter filter) { | 51 | Tegra::Texture::TextureFilter filter) { |
| 52 | switch (wrap_mode) { | 52 | switch (wrap_mode) { |
| 53 | case Tegra::Texture::WrapMode::Wrap: | 53 | case Tegra::Texture::WrapMode::Wrap: |
| @@ -79,7 +79,7 @@ VkSamplerAddressMode WrapMode(const VKDevice& device, Tegra::Texture::WrapMode w | |||
| 79 | UNIMPLEMENTED(); | 79 | UNIMPLEMENTED(); |
| 80 | return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; | 80 | return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| 81 | default: | 81 | default: |
| 82 | UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", static_cast<u32>(wrap_mode)); | 82 | UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", wrap_mode); |
| 83 | return {}; | 83 | return {}; |
| 84 | } | 84 | } |
| 85 | } | 85 | } |
| @@ -103,8 +103,7 @@ VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_ | |||
| 103 | case Tegra::Texture::DepthCompareFunc::Always: | 103 | case Tegra::Texture::DepthCompareFunc::Always: |
| 104 | return VK_COMPARE_OP_ALWAYS; | 104 | return VK_COMPARE_OP_ALWAYS; |
| 105 | } | 105 | } |
| 106 | UNIMPLEMENTED_MSG("Unimplemented sampler depth compare function={}", | 106 | UNIMPLEMENTED_MSG("Unimplemented sampler depth compare function={}", depth_compare_func); |
| 107 | static_cast<u32>(depth_compare_func)); | ||
| 108 | return {}; | 107 | return {}; |
| 109 | } | 108 | } |
| 110 | 109 | ||
| @@ -123,7 +122,7 @@ struct FormatTuple { | |||
| 123 | {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT | 122 | {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT |
| 124 | {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT | 123 | {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT |
| 125 | {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM | 124 | {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM |
| 126 | {VK_FORMAT_B5G6R5_UNORM_PACK16, Attachable}, // B5G6R5_UNORM | 125 | {VK_FORMAT_B5G6R5_UNORM_PACK16}, // B5G6R5_UNORM |
| 127 | {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM | 126 | {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM |
| 128 | {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM | 127 | {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM |
| 129 | {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT | 128 | {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT |
| @@ -164,7 +163,7 @@ struct FormatTuple { | |||
| 164 | {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM | 163 | {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM |
| 165 | {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT | 164 | {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT |
| 166 | {VK_FORMAT_UNDEFINED}, // R16G16_UINT | 165 | {VK_FORMAT_UNDEFINED}, // R16G16_UINT |
| 167 | {VK_FORMAT_UNDEFINED}, // R16G16_SINT | 166 | {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT |
| 168 | {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM | 167 | {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM |
| 169 | {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT | 168 | {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT |
| 170 | {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB | 169 | {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB |
| @@ -223,30 +222,31 @@ constexpr bool IsZetaFormat(PixelFormat pixel_format) { | |||
| 223 | 222 | ||
| 224 | } // Anonymous namespace | 223 | } // Anonymous namespace |
| 225 | 224 | ||
| 226 | FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFormat pixel_format) { | 225 | FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format) { |
| 227 | ASSERT(static_cast<std::size_t>(pixel_format) < std::size(tex_format_tuples)); | 226 | ASSERT(static_cast<std::size_t>(pixel_format) < std::size(tex_format_tuples)); |
| 228 | 227 | ||
| 229 | auto tuple = tex_format_tuples[static_cast<std::size_t>(pixel_format)]; | 228 | auto tuple = tex_format_tuples[static_cast<std::size_t>(pixel_format)]; |
| 230 | if (tuple.format == VK_FORMAT_UNDEFINED) { | 229 | if (tuple.format == VK_FORMAT_UNDEFINED) { |
| 231 | UNIMPLEMENTED_MSG("Unimplemented texture format with pixel format={}", | 230 | UNIMPLEMENTED_MSG("Unimplemented texture format with pixel format={}", pixel_format); |
| 232 | static_cast<u32>(pixel_format)); | ||
| 233 | return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; | 231 | return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; |
| 234 | } | 232 | } |
| 235 | 233 | ||
| 236 | // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively | 234 | // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively |
| 237 | if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { | 235 | if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { |
| 238 | tuple.format = VideoCore::Surface::IsPixelFormatSRGB(pixel_format) | 236 | const bool is_srgb = VideoCore::Surface::IsPixelFormatSRGB(pixel_format); |
| 239 | ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 | 237 | tuple.format = is_srgb ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 : VK_FORMAT_A8B8G8R8_UNORM_PACK32; |
| 240 | : VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 241 | } | 238 | } |
| 242 | const bool attachable = tuple.usage & Attachable; | 239 | const bool attachable = tuple.usage & Attachable; |
| 243 | const bool storage = tuple.usage & Storage; | 240 | const bool storage = tuple.usage & Storage; |
| 244 | 241 | ||
| 245 | VkFormatFeatureFlags usage; | 242 | VkFormatFeatureFlags usage{}; |
| 246 | if (format_type == FormatType::Buffer) { | 243 | switch (format_type) { |
| 244 | case FormatType::Buffer: | ||
| 247 | usage = | 245 | usage = |
| 248 | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT; | 246 | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT; |
| 249 | } else { | 247 | break; |
| 248 | case FormatType::Linear: | ||
| 249 | case FormatType::Optimal: | ||
| 250 | usage = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT | | 250 | usage = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT | |
| 251 | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT; | 251 | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT; |
| 252 | if (attachable) { | 252 | if (attachable) { |
| @@ -256,6 +256,7 @@ FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFo | |||
| 256 | if (storage) { | 256 | if (storage) { |
| 257 | usage |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; | 257 | usage |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; |
| 258 | } | 258 | } |
| 259 | break; | ||
| 259 | } | 260 | } |
| 260 | return {device.GetSupportedFormat(tuple.format, usage, format_type), attachable, storage}; | 261 | return {device.GetSupportedFormat(tuple.format, usage, format_type), attachable, storage}; |
| 261 | } | 262 | } |
| @@ -275,11 +276,11 @@ VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage) { | |||
| 275 | case Tegra::Engines::ShaderType::Compute: | 276 | case Tegra::Engines::ShaderType::Compute: |
| 276 | return VK_SHADER_STAGE_COMPUTE_BIT; | 277 | return VK_SHADER_STAGE_COMPUTE_BIT; |
| 277 | } | 278 | } |
| 278 | UNIMPLEMENTED_MSG("Unimplemented shader stage={}", static_cast<u32>(stage)); | 279 | UNIMPLEMENTED_MSG("Unimplemented shader stage={}", stage); |
| 279 | return {}; | 280 | return {}; |
| 280 | } | 281 | } |
| 281 | 282 | ||
| 282 | VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const VKDevice& device, | 283 | VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const Device& device, |
| 283 | Maxwell::PrimitiveTopology topology) { | 284 | Maxwell::PrimitiveTopology topology) { |
| 284 | switch (topology) { | 285 | switch (topology) { |
| 285 | case Maxwell::PrimitiveTopology::Points: | 286 | case Maxwell::PrimitiveTopology::Points: |
| @@ -300,7 +301,7 @@ VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const VKDevice& device, | |||
| 300 | case Maxwell::PrimitiveTopology::Patches: | 301 | case Maxwell::PrimitiveTopology::Patches: |
| 301 | return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; | 302 | return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; |
| 302 | default: | 303 | default: |
| 303 | UNIMPLEMENTED_MSG("Unimplemented topology={}", static_cast<u32>(topology)); | 304 | UNIMPLEMENTED_MSG("Unimplemented topology={}", topology); |
| 304 | return {}; | 305 | return {}; |
| 305 | } | 306 | } |
| 306 | } | 307 | } |
| @@ -490,8 +491,7 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib | |||
| 490 | } | 491 | } |
| 491 | break; | 492 | break; |
| 492 | } | 493 | } |
| 493 | UNIMPLEMENTED_MSG("Unimplemented vertex format of type={} and size={}", static_cast<u32>(type), | 494 | UNIMPLEMENTED_MSG("Unimplemented vertex format of type={} and size={}", type, size); |
| 494 | static_cast<u32>(size)); | ||
| 495 | return {}; | 495 | return {}; |
| 496 | } | 496 | } |
| 497 | 497 | ||
| @@ -522,11 +522,11 @@ VkCompareOp ComparisonOp(Maxwell::ComparisonOp comparison) { | |||
| 522 | case Maxwell::ComparisonOp::AlwaysOld: | 522 | case Maxwell::ComparisonOp::AlwaysOld: |
| 523 | return VK_COMPARE_OP_ALWAYS; | 523 | return VK_COMPARE_OP_ALWAYS; |
| 524 | } | 524 | } |
| 525 | UNIMPLEMENTED_MSG("Unimplemented comparison op={}", static_cast<u32>(comparison)); | 525 | UNIMPLEMENTED_MSG("Unimplemented comparison op={}", comparison); |
| 526 | return {}; | 526 | return {}; |
| 527 | } | 527 | } |
| 528 | 528 | ||
| 529 | VkIndexType IndexFormat(const VKDevice& device, Maxwell::IndexFormat index_format) { | 529 | VkIndexType IndexFormat(const Device& device, Maxwell::IndexFormat index_format) { |
| 530 | switch (index_format) { | 530 | switch (index_format) { |
| 531 | case Maxwell::IndexFormat::UnsignedByte: | 531 | case Maxwell::IndexFormat::UnsignedByte: |
| 532 | if (!device.IsExtIndexTypeUint8Supported()) { | 532 | if (!device.IsExtIndexTypeUint8Supported()) { |
| @@ -539,7 +539,7 @@ VkIndexType IndexFormat(const VKDevice& device, Maxwell::IndexFormat index_forma | |||
| 539 | case Maxwell::IndexFormat::UnsignedInt: | 539 | case Maxwell::IndexFormat::UnsignedInt: |
| 540 | return VK_INDEX_TYPE_UINT32; | 540 | return VK_INDEX_TYPE_UINT32; |
| 541 | } | 541 | } |
| 542 | UNIMPLEMENTED_MSG("Unimplemented index_format={}", static_cast<u32>(index_format)); | 542 | UNIMPLEMENTED_MSG("Unimplemented index_format={}", index_format); |
| 543 | return {}; | 543 | return {}; |
| 544 | } | 544 | } |
| 545 | 545 | ||
| @@ -570,7 +570,7 @@ VkStencilOp StencilOp(Maxwell::StencilOp stencil_op) { | |||
| 570 | case Maxwell::StencilOp::DecrWrapOGL: | 570 | case Maxwell::StencilOp::DecrWrapOGL: |
| 571 | return VK_STENCIL_OP_DECREMENT_AND_WRAP; | 571 | return VK_STENCIL_OP_DECREMENT_AND_WRAP; |
| 572 | } | 572 | } |
| 573 | UNIMPLEMENTED_MSG("Unimplemented stencil op={}", static_cast<u32>(stencil_op)); | 573 | UNIMPLEMENTED_MSG("Unimplemented stencil op={}", stencil_op); |
| 574 | return {}; | 574 | return {}; |
| 575 | } | 575 | } |
| 576 | 576 | ||
| @@ -592,7 +592,7 @@ VkBlendOp BlendEquation(Maxwell::Blend::Equation equation) { | |||
| 592 | case Maxwell::Blend::Equation::MaxGL: | 592 | case Maxwell::Blend::Equation::MaxGL: |
| 593 | return VK_BLEND_OP_MAX; | 593 | return VK_BLEND_OP_MAX; |
| 594 | } | 594 | } |
| 595 | UNIMPLEMENTED_MSG("Unimplemented blend equation={}", static_cast<u32>(equation)); | 595 | UNIMPLEMENTED_MSG("Unimplemented blend equation={}", equation); |
| 596 | return {}; | 596 | return {}; |
| 597 | } | 597 | } |
| 598 | 598 | ||
| @@ -656,7 +656,7 @@ VkBlendFactor BlendFactor(Maxwell::Blend::Factor factor) { | |||
| 656 | case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: | 656 | case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: |
| 657 | return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; | 657 | return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; |
| 658 | } | 658 | } |
| 659 | UNIMPLEMENTED_MSG("Unimplemented blend factor={}", static_cast<u32>(factor)); | 659 | UNIMPLEMENTED_MSG("Unimplemented blend factor={}", factor); |
| 660 | return {}; | 660 | return {}; |
| 661 | } | 661 | } |
| 662 | 662 | ||
| @@ -667,7 +667,7 @@ VkFrontFace FrontFace(Maxwell::FrontFace front_face) { | |||
| 667 | case Maxwell::FrontFace::CounterClockWise: | 667 | case Maxwell::FrontFace::CounterClockWise: |
| 668 | return VK_FRONT_FACE_COUNTER_CLOCKWISE; | 668 | return VK_FRONT_FACE_COUNTER_CLOCKWISE; |
| 669 | } | 669 | } |
| 670 | UNIMPLEMENTED_MSG("Unimplemented front face={}", static_cast<u32>(front_face)); | 670 | UNIMPLEMENTED_MSG("Unimplemented front face={}", front_face); |
| 671 | return {}; | 671 | return {}; |
| 672 | } | 672 | } |
| 673 | 673 | ||
| @@ -680,7 +680,7 @@ VkCullModeFlags CullFace(Maxwell::CullFace cull_face) { | |||
| 680 | case Maxwell::CullFace::FrontAndBack: | 680 | case Maxwell::CullFace::FrontAndBack: |
| 681 | return VK_CULL_MODE_FRONT_AND_BACK; | 681 | return VK_CULL_MODE_FRONT_AND_BACK; |
| 682 | } | 682 | } |
| 683 | UNIMPLEMENTED_MSG("Unimplemented cull face={}", static_cast<u32>(cull_face)); | 683 | UNIMPLEMENTED_MSG("Unimplemented cull face={}", cull_face); |
| 684 | return {}; | 684 | return {}; |
| 685 | } | 685 | } |
| 686 | 686 | ||
| @@ -700,7 +700,7 @@ VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle) { | |||
| 700 | case Tegra::Texture::SwizzleSource::OneFloat: | 700 | case Tegra::Texture::SwizzleSource::OneFloat: |
| 701 | return VK_COMPONENT_SWIZZLE_ONE; | 701 | return VK_COMPONENT_SWIZZLE_ONE; |
| 702 | } | 702 | } |
| 703 | UNIMPLEMENTED_MSG("Unimplemented swizzle source={}", static_cast<u32>(swizzle)); | 703 | UNIMPLEMENTED_MSG("Unimplemented swizzle source={}", swizzle); |
| 704 | return {}; | 704 | return {}; |
| 705 | } | 705 | } |
| 706 | 706 | ||
| @@ -723,8 +723,21 @@ VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle) | |||
| 723 | case Maxwell::ViewportSwizzle::NegativeW: | 723 | case Maxwell::ViewportSwizzle::NegativeW: |
| 724 | return VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV; | 724 | return VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV; |
| 725 | } | 725 | } |
| 726 | UNREACHABLE_MSG("Invalid swizzle={}", static_cast<int>(swizzle)); | 726 | UNREACHABLE_MSG("Invalid swizzle={}", swizzle); |
| 727 | return {}; | 727 | return {}; |
| 728 | } | 728 | } |
| 729 | 729 | ||
| 730 | VkSamplerReductionMode SamplerReduction(Tegra::Texture::SamplerReduction reduction) { | ||
| 731 | switch (reduction) { | ||
| 732 | case Tegra::Texture::SamplerReduction::WeightedAverage: | ||
| 733 | return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT; | ||
| 734 | case Tegra::Texture::SamplerReduction::Min: | ||
| 735 | return VK_SAMPLER_REDUCTION_MODE_MIN_EXT; | ||
| 736 | case Tegra::Texture::SamplerReduction::Max: | ||
| 737 | return VK_SAMPLER_REDUCTION_MODE_MAX_EXT; | ||
| 738 | } | ||
| 739 | UNREACHABLE_MSG("Invalid sampler mode={}", static_cast<int>(reduction)); | ||
| 740 | return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT; | ||
| 741 | } | ||
| 742 | |||
| 730 | } // namespace Vulkan::MaxwellToVK | 743 | } // namespace Vulkan::MaxwellToVK |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h index 7e213452f..537969840 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.h +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h | |||
| @@ -6,10 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "video_core/engines/maxwell_3d.h" | 8 | #include "video_core/engines/maxwell_3d.h" |
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 10 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 11 | #include "video_core/surface.h" | 9 | #include "video_core/surface.h" |
| 12 | #include "video_core/textures/texture.h" | 10 | #include "video_core/textures/texture.h" |
| 11 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | 13 | ||
| 14 | namespace Vulkan::MaxwellToVK { | 14 | namespace Vulkan::MaxwellToVK { |
| 15 | 15 | ||
| @@ -22,7 +22,7 @@ VkFilter Filter(Tegra::Texture::TextureFilter filter); | |||
| 22 | 22 | ||
| 23 | VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter); | 23 | VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter); |
| 24 | 24 | ||
| 25 | VkSamplerAddressMode WrapMode(const VKDevice& device, Tegra::Texture::WrapMode wrap_mode, | 25 | VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wrap_mode, |
| 26 | Tegra::Texture::TextureFilter filter); | 26 | Tegra::Texture::TextureFilter filter); |
| 27 | 27 | ||
| 28 | VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_func); | 28 | VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_func); |
| @@ -35,17 +35,17 @@ struct FormatInfo { | |||
| 35 | bool storage; | 35 | bool storage; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFormat pixel_format); | 38 | FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format); |
| 39 | 39 | ||
| 40 | VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage); | 40 | VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage); |
| 41 | 41 | ||
| 42 | VkPrimitiveTopology PrimitiveTopology(const VKDevice& device, Maxwell::PrimitiveTopology topology); | 42 | VkPrimitiveTopology PrimitiveTopology(const Device& device, Maxwell::PrimitiveTopology topology); |
| 43 | 43 | ||
| 44 | VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size); | 44 | VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size); |
| 45 | 45 | ||
| 46 | VkCompareOp ComparisonOp(Maxwell::ComparisonOp comparison); | 46 | VkCompareOp ComparisonOp(Maxwell::ComparisonOp comparison); |
| 47 | 47 | ||
| 48 | VkIndexType IndexFormat(const VKDevice& device, Maxwell::IndexFormat index_format); | 48 | VkIndexType IndexFormat(const Device& device, Maxwell::IndexFormat index_format); |
| 49 | 49 | ||
| 50 | VkStencilOp StencilOp(Maxwell::StencilOp stencil_op); | 50 | VkStencilOp StencilOp(Maxwell::StencilOp stencil_op); |
| 51 | 51 | ||
| @@ -61,4 +61,6 @@ VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle); | |||
| 61 | 61 | ||
| 62 | VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle); | 62 | VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle); |
| 63 | 63 | ||
| 64 | VkSamplerReductionMode SamplerReduction(Tegra::Texture::SamplerReduction reduction); | ||
| 65 | |||
| 64 | } // namespace Vulkan::MaxwellToVK | 66 | } // namespace Vulkan::MaxwellToVK |
diff --git a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp b/src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp deleted file mode 100644 index 5b01020ec..000000000 --- a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp +++ /dev/null | |||
| @@ -1,220 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #ifdef HAS_NSIGHT_AFTERMATH | ||
| 6 | |||
| 7 | #include <mutex> | ||
| 8 | #include <string> | ||
| 9 | #include <string_view> | ||
| 10 | #include <utility> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | #include <fmt/format.h> | ||
| 14 | |||
| 15 | #define VK_NO_PROTOTYPES | ||
| 16 | #include <vulkan/vulkan.h> | ||
| 17 | |||
| 18 | #include <GFSDK_Aftermath.h> | ||
| 19 | #include <GFSDK_Aftermath_Defines.h> | ||
| 20 | #include <GFSDK_Aftermath_GpuCrashDump.h> | ||
| 21 | #include <GFSDK_Aftermath_GpuCrashDumpDecoding.h> | ||
| 22 | |||
| 23 | #include "common/common_paths.h" | ||
| 24 | #include "common/common_types.h" | ||
| 25 | #include "common/file_util.h" | ||
| 26 | #include "common/logging/log.h" | ||
| 27 | #include "common/scope_exit.h" | ||
| 28 | |||
| 29 | #include "video_core/renderer_vulkan/nsight_aftermath_tracker.h" | ||
| 30 | |||
| 31 | namespace Vulkan { | ||
| 32 | |||
| 33 | static constexpr char AFTERMATH_LIB_NAME[] = "GFSDK_Aftermath_Lib.x64.dll"; | ||
| 34 | |||
| 35 | NsightAftermathTracker::NsightAftermathTracker() = default; | ||
| 36 | |||
| 37 | NsightAftermathTracker::~NsightAftermathTracker() { | ||
| 38 | if (initialized) { | ||
| 39 | (void)GFSDK_Aftermath_DisableGpuCrashDumps(); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | bool NsightAftermathTracker::Initialize() { | ||
| 44 | if (!dl.Open(AFTERMATH_LIB_NAME)) { | ||
| 45 | LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath DLL"); | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | if (!dl.GetSymbol("GFSDK_Aftermath_DisableGpuCrashDumps", | ||
| 50 | &GFSDK_Aftermath_DisableGpuCrashDumps) || | ||
| 51 | !dl.GetSymbol("GFSDK_Aftermath_EnableGpuCrashDumps", | ||
| 52 | &GFSDK_Aftermath_EnableGpuCrashDumps) || | ||
| 53 | !dl.GetSymbol("GFSDK_Aftermath_GetShaderDebugInfoIdentifier", | ||
| 54 | &GFSDK_Aftermath_GetShaderDebugInfoIdentifier) || | ||
| 55 | !dl.GetSymbol("GFSDK_Aftermath_GetShaderHashSpirv", &GFSDK_Aftermath_GetShaderHashSpirv) || | ||
| 56 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_CreateDecoder", | ||
| 57 | &GFSDK_Aftermath_GpuCrashDump_CreateDecoder) || | ||
| 58 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_DestroyDecoder", | ||
| 59 | &GFSDK_Aftermath_GpuCrashDump_DestroyDecoder) || | ||
| 60 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GenerateJSON", | ||
| 61 | &GFSDK_Aftermath_GpuCrashDump_GenerateJSON) || | ||
| 62 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON", | ||
| 63 | &GFSDK_Aftermath_GpuCrashDump_GetJSON)) { | ||
| 64 | LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers"); | ||
| 65 | return false; | ||
| 66 | } | ||
| 67 | |||
| 68 | dump_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + "gpucrash"; | ||
| 69 | |||
| 70 | (void)Common::FS::DeleteDirRecursively(dump_dir); | ||
| 71 | if (!Common::FS::CreateDir(dump_dir)) { | ||
| 72 | LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory"); | ||
| 73 | return false; | ||
| 74 | } | ||
| 75 | |||
| 76 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_EnableGpuCrashDumps( | ||
| 77 | GFSDK_Aftermath_Version_API, GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan, | ||
| 78 | GFSDK_Aftermath_GpuCrashDumpFeatureFlags_Default, GpuCrashDumpCallback, | ||
| 79 | ShaderDebugInfoCallback, CrashDumpDescriptionCallback, this))) { | ||
| 80 | LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_EnableGpuCrashDumps failed"); | ||
| 81 | return false; | ||
| 82 | } | ||
| 83 | |||
| 84 | LOG_INFO(Render_Vulkan, "Nsight Aftermath dump directory is \"{}\"", dump_dir); | ||
| 85 | |||
| 86 | initialized = true; | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | |||
| 90 | void NsightAftermathTracker::SaveShader(const std::vector<u32>& spirv) const { | ||
| 91 | if (!initialized) { | ||
| 92 | return; | ||
| 93 | } | ||
| 94 | |||
| 95 | std::vector<u32> spirv_copy = spirv; | ||
| 96 | GFSDK_Aftermath_SpirvCode shader; | ||
| 97 | shader.pData = spirv_copy.data(); | ||
| 98 | shader.size = static_cast<u32>(spirv_copy.size() * 4); | ||
| 99 | |||
| 100 | std::scoped_lock lock{mutex}; | ||
| 101 | |||
| 102 | GFSDK_Aftermath_ShaderHash hash; | ||
| 103 | if (!GFSDK_Aftermath_SUCCEED( | ||
| 104 | GFSDK_Aftermath_GetShaderHashSpirv(GFSDK_Aftermath_Version_API, &shader, &hash))) { | ||
| 105 | LOG_ERROR(Render_Vulkan, "Failed to hash SPIR-V module"); | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | |||
| 109 | Common::FS::IOFile file(fmt::format("{}/source_{:016x}.spv", dump_dir, hash.hash), "wb"); | ||
| 110 | if (!file.IsOpen()) { | ||
| 111 | LOG_ERROR(Render_Vulkan, "Failed to dump SPIR-V module with hash={:016x}", hash.hash); | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | if (file.WriteArray(spirv.data(), spirv.size()) != spirv.size()) { | ||
| 115 | LOG_ERROR(Render_Vulkan, "Failed to write SPIR-V module with hash={:016x}", hash.hash); | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump, | ||
| 121 | u32 gpu_crash_dump_size) { | ||
| 122 | std::scoped_lock lock{mutex}; | ||
| 123 | |||
| 124 | LOG_CRITICAL(Render_Vulkan, "called"); | ||
| 125 | |||
| 126 | GFSDK_Aftermath_GpuCrashDump_Decoder decoder; | ||
| 127 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_CreateDecoder( | ||
| 128 | GFSDK_Aftermath_Version_API, gpu_crash_dump, gpu_crash_dump_size, &decoder))) { | ||
| 129 | LOG_ERROR(Render_Vulkan, "Failed to create decoder"); | ||
| 130 | return; | ||
| 131 | } | ||
| 132 | SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); }); | ||
| 133 | |||
| 134 | u32 json_size = 0; | ||
| 135 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON( | ||
| 136 | decoder, GFSDK_Aftermath_GpuCrashDumpDecoderFlags_ALL_INFO, | ||
| 137 | GFSDK_Aftermath_GpuCrashDumpFormatterFlags_NONE, nullptr, nullptr, nullptr, nullptr, | ||
| 138 | this, &json_size))) { | ||
| 139 | LOG_ERROR(Render_Vulkan, "Failed to generate JSON"); | ||
| 140 | return; | ||
| 141 | } | ||
| 142 | std::vector<char> json(json_size); | ||
| 143 | if (!GFSDK_Aftermath_SUCCEED( | ||
| 144 | GFSDK_Aftermath_GpuCrashDump_GetJSON(decoder, json_size, json.data()))) { | ||
| 145 | LOG_ERROR(Render_Vulkan, "Failed to query JSON"); | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | |||
| 149 | const std::string base_name = [this] { | ||
| 150 | const int id = dump_id++; | ||
| 151 | if (id == 0) { | ||
| 152 | return fmt::format("{}/crash.nv-gpudmp", dump_dir); | ||
| 153 | } else { | ||
| 154 | return fmt::format("{}/crash_{}.nv-gpudmp", dump_dir, id); | ||
| 155 | } | ||
| 156 | }(); | ||
| 157 | |||
| 158 | std::string_view dump_view(static_cast<const char*>(gpu_crash_dump), gpu_crash_dump_size); | ||
| 159 | if (Common::FS::WriteStringToFile(false, base_name, dump_view) != gpu_crash_dump_size) { | ||
| 160 | LOG_ERROR(Render_Vulkan, "Failed to write dump file"); | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | const std::string_view json_view(json.data(), json.size()); | ||
| 164 | if (Common::FS::WriteStringToFile(true, base_name + ".json", json_view) != json.size()) { | ||
| 165 | LOG_ERROR(Render_Vulkan, "Failed to write JSON"); | ||
| 166 | return; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | void NsightAftermathTracker::OnShaderDebugInfoCallback(const void* shader_debug_info, | ||
| 171 | u32 shader_debug_info_size) { | ||
| 172 | std::scoped_lock lock{mutex}; | ||
| 173 | |||
| 174 | GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier; | ||
| 175 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GetShaderDebugInfoIdentifier( | ||
| 176 | GFSDK_Aftermath_Version_API, shader_debug_info, shader_debug_info_size, &identifier))) { | ||
| 177 | LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_GetShaderDebugInfoIdentifier failed"); | ||
| 178 | return; | ||
| 179 | } | ||
| 180 | |||
| 181 | const std::string path = | ||
| 182 | fmt::format("{}/shader_{:016x}{:016x}.nvdbg", dump_dir, identifier.id[0], identifier.id[1]); | ||
| 183 | Common::FS::IOFile file(path, "wb"); | ||
| 184 | if (!file.IsOpen()) { | ||
| 185 | LOG_ERROR(Render_Vulkan, "Failed to create file {}", path); | ||
| 186 | return; | ||
| 187 | } | ||
| 188 | if (file.WriteBytes(static_cast<const u8*>(shader_debug_info), shader_debug_info_size) != | ||
| 189 | shader_debug_info_size) { | ||
| 190 | LOG_ERROR(Render_Vulkan, "Failed to write file {}", path); | ||
| 191 | return; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | void NsightAftermathTracker::OnCrashDumpDescriptionCallback( | ||
| 196 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description) { | ||
| 197 | add_description(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName, "yuzu"); | ||
| 198 | } | ||
| 199 | |||
| 200 | void NsightAftermathTracker::GpuCrashDumpCallback(const void* gpu_crash_dump, | ||
| 201 | u32 gpu_crash_dump_size, void* user_data) { | ||
| 202 | static_cast<NsightAftermathTracker*>(user_data)->OnGpuCrashDumpCallback(gpu_crash_dump, | ||
| 203 | gpu_crash_dump_size); | ||
| 204 | } | ||
| 205 | |||
| 206 | void NsightAftermathTracker::ShaderDebugInfoCallback(const void* shader_debug_info, | ||
| 207 | u32 shader_debug_info_size, void* user_data) { | ||
| 208 | static_cast<NsightAftermathTracker*>(user_data)->OnShaderDebugInfoCallback( | ||
| 209 | shader_debug_info, shader_debug_info_size); | ||
| 210 | } | ||
| 211 | |||
| 212 | void NsightAftermathTracker::CrashDumpDescriptionCallback( | ||
| 213 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data) { | ||
| 214 | static_cast<NsightAftermathTracker*>(user_data)->OnCrashDumpDescriptionCallback( | ||
| 215 | add_description); | ||
| 216 | } | ||
| 217 | |||
| 218 | } // namespace Vulkan | ||
| 219 | |||
| 220 | #endif // HAS_NSIGHT_AFTERMATH | ||
diff --git a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h b/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h deleted file mode 100644 index afe7ae99e..000000000 --- a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h +++ /dev/null | |||
| @@ -1,87 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <mutex> | ||
| 8 | #include <string> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #define VK_NO_PROTOTYPES | ||
| 12 | #include <vulkan/vulkan.h> | ||
| 13 | |||
| 14 | #ifdef HAS_NSIGHT_AFTERMATH | ||
| 15 | #include <GFSDK_Aftermath_Defines.h> | ||
| 16 | #include <GFSDK_Aftermath_GpuCrashDump.h> | ||
| 17 | #include <GFSDK_Aftermath_GpuCrashDumpDecoding.h> | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #include "common/common_types.h" | ||
| 21 | #include "common/dynamic_library.h" | ||
| 22 | |||
| 23 | namespace Vulkan { | ||
| 24 | |||
| 25 | class NsightAftermathTracker { | ||
| 26 | public: | ||
| 27 | NsightAftermathTracker(); | ||
| 28 | ~NsightAftermathTracker(); | ||
| 29 | |||
| 30 | NsightAftermathTracker(const NsightAftermathTracker&) = delete; | ||
| 31 | NsightAftermathTracker& operator=(const NsightAftermathTracker&) = delete; | ||
| 32 | |||
| 33 | // Delete move semantics because Aftermath initialization uses a pointer to this. | ||
| 34 | NsightAftermathTracker(NsightAftermathTracker&&) = delete; | ||
| 35 | NsightAftermathTracker& operator=(NsightAftermathTracker&&) = delete; | ||
| 36 | |||
| 37 | bool Initialize(); | ||
| 38 | |||
| 39 | void SaveShader(const std::vector<u32>& spirv) const; | ||
| 40 | |||
| 41 | private: | ||
| 42 | #ifdef HAS_NSIGHT_AFTERMATH | ||
| 43 | static void GpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size, | ||
| 44 | void* user_data); | ||
| 45 | |||
| 46 | static void ShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size, | ||
| 47 | void* user_data); | ||
| 48 | |||
| 49 | static void CrashDumpDescriptionCallback( | ||
| 50 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data); | ||
| 51 | |||
| 52 | void OnGpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size); | ||
| 53 | |||
| 54 | void OnShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size); | ||
| 55 | |||
| 56 | void OnCrashDumpDescriptionCallback( | ||
| 57 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description); | ||
| 58 | |||
| 59 | mutable std::mutex mutex; | ||
| 60 | |||
| 61 | std::string dump_dir; | ||
| 62 | int dump_id = 0; | ||
| 63 | |||
| 64 | bool initialized = false; | ||
| 65 | |||
| 66 | Common::DynamicLibrary dl; | ||
| 67 | PFN_GFSDK_Aftermath_DisableGpuCrashDumps GFSDK_Aftermath_DisableGpuCrashDumps; | ||
| 68 | PFN_GFSDK_Aftermath_EnableGpuCrashDumps GFSDK_Aftermath_EnableGpuCrashDumps; | ||
| 69 | PFN_GFSDK_Aftermath_GetShaderDebugInfoIdentifier GFSDK_Aftermath_GetShaderDebugInfoIdentifier; | ||
| 70 | PFN_GFSDK_Aftermath_GetShaderHashSpirv GFSDK_Aftermath_GetShaderHashSpirv; | ||
| 71 | PFN_GFSDK_Aftermath_GpuCrashDump_CreateDecoder GFSDK_Aftermath_GpuCrashDump_CreateDecoder; | ||
| 72 | PFN_GFSDK_Aftermath_GpuCrashDump_DestroyDecoder GFSDK_Aftermath_GpuCrashDump_DestroyDecoder; | ||
| 73 | PFN_GFSDK_Aftermath_GpuCrashDump_GenerateJSON GFSDK_Aftermath_GpuCrashDump_GenerateJSON; | ||
| 74 | PFN_GFSDK_Aftermath_GpuCrashDump_GetJSON GFSDK_Aftermath_GpuCrashDump_GetJSON; | ||
| 75 | #endif | ||
| 76 | }; | ||
| 77 | |||
| 78 | #ifndef HAS_NSIGHT_AFTERMATH | ||
| 79 | inline NsightAftermathTracker::NsightAftermathTracker() = default; | ||
| 80 | inline NsightAftermathTracker::~NsightAftermathTracker() = default; | ||
| 81 | inline bool NsightAftermathTracker::Initialize() { | ||
| 82 | return false; | ||
| 83 | } | ||
| 84 | inline void NsightAftermathTracker::SaveShader(const std::vector<u32>&) const {} | ||
| 85 | #endif | ||
| 86 | |||
| 87 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 715182b3b..d7437e185 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -12,8 +12,6 @@ | |||
| 12 | 12 | ||
| 13 | #include <fmt/format.h> | 13 | #include <fmt/format.h> |
| 14 | 14 | ||
| 15 | #include "common/dynamic_library.h" | ||
| 16 | #include "common/file_util.h" | ||
| 17 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 18 | #include "common/telemetry.h" | 16 | #include "common/telemetry.h" |
| 19 | #include "core/core.h" | 17 | #include "core/core.h" |
| @@ -24,179 +22,27 @@ | |||
| 24 | #include "video_core/gpu.h" | 22 | #include "video_core/gpu.h" |
| 25 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 23 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 26 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 24 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 27 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 28 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 29 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 26 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 30 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 27 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 31 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 28 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 32 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 29 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 33 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 30 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 34 | #include "video_core/renderer_vulkan/wrapper.h" | 31 | #include "video_core/vulkan_common/vulkan_debug_callback.h" |
| 35 | 32 | #include "video_core/vulkan_common/vulkan_device.h" | |
| 36 | // Include these late to avoid polluting previous headers | 33 | #include "video_core/vulkan_common/vulkan_instance.h" |
| 37 | #ifdef _WIN32 | 34 | #include "video_core/vulkan_common/vulkan_library.h" |
| 38 | #include <windows.h> | 35 | #include "video_core/vulkan_common/vulkan_surface.h" |
| 39 | // ensure include order | 36 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 40 | #include <vulkan/vulkan_win32.h> | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #if !defined(_WIN32) && !defined(__APPLE__) | ||
| 44 | #include <X11/Xlib.h> | ||
| 45 | #include <vulkan/vulkan_wayland.h> | ||
| 46 | #include <vulkan/vulkan_xlib.h> | ||
| 47 | #endif | ||
| 48 | 37 | ||
| 49 | namespace Vulkan { | 38 | namespace Vulkan { |
| 50 | |||
| 51 | namespace { | 39 | namespace { |
| 52 | |||
| 53 | using Core::Frontend::WindowSystemType; | ||
| 54 | |||
| 55 | VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, | ||
| 56 | VkDebugUtilsMessageTypeFlagsEXT type, | ||
| 57 | const VkDebugUtilsMessengerCallbackDataEXT* data, | ||
| 58 | [[maybe_unused]] void* user_data) { | ||
| 59 | const char* const message{data->pMessage}; | ||
| 60 | |||
| 61 | if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { | ||
| 62 | LOG_CRITICAL(Render_Vulkan, "{}", message); | ||
| 63 | } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { | ||
| 64 | LOG_WARNING(Render_Vulkan, "{}", message); | ||
| 65 | } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { | ||
| 66 | LOG_INFO(Render_Vulkan, "{}", message); | ||
| 67 | } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { | ||
| 68 | LOG_DEBUG(Render_Vulkan, "{}", message); | ||
| 69 | } | ||
| 70 | return VK_FALSE; | ||
| 71 | } | ||
| 72 | |||
| 73 | Common::DynamicLibrary OpenVulkanLibrary() { | ||
| 74 | Common::DynamicLibrary library; | ||
| 75 | #ifdef __APPLE__ | ||
| 76 | // Check if a path to a specific Vulkan library has been specified. | ||
| 77 | char* libvulkan_env = getenv("LIBVULKAN_PATH"); | ||
| 78 | if (!libvulkan_env || !library.Open(libvulkan_env)) { | ||
| 79 | // Use the libvulkan.dylib from the application bundle. | ||
| 80 | const std::string filename = | ||
| 81 | Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; | ||
| 82 | library.Open(filename.c_str()); | ||
| 83 | } | ||
| 84 | #else | ||
| 85 | std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); | ||
| 86 | if (!library.Open(filename.c_str())) { | ||
| 87 | // Android devices may not have libvulkan.so.1, only libvulkan.so. | ||
| 88 | filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); | ||
| 89 | (void)library.Open(filename.c_str()); | ||
| 90 | } | ||
| 91 | #endif | ||
| 92 | return library; | ||
| 93 | } | ||
| 94 | |||
| 95 | vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatch& dld, | ||
| 96 | WindowSystemType window_type = WindowSystemType::Headless, | ||
| 97 | bool enable_layers = false) { | ||
| 98 | if (!library.IsOpen()) { | ||
| 99 | LOG_ERROR(Render_Vulkan, "Vulkan library not available"); | ||
| 100 | return {}; | ||
| 101 | } | ||
| 102 | if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) { | ||
| 103 | LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan"); | ||
| 104 | return {}; | ||
| 105 | } | ||
| 106 | if (!vk::Load(dld)) { | ||
| 107 | LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); | ||
| 108 | return {}; | ||
| 109 | } | ||
| 110 | |||
| 111 | std::vector<const char*> extensions; | ||
| 112 | extensions.reserve(6); | ||
| 113 | switch (window_type) { | ||
| 114 | case Core::Frontend::WindowSystemType::Headless: | ||
| 115 | break; | ||
| 116 | #ifdef _WIN32 | ||
| 117 | case Core::Frontend::WindowSystemType::Windows: | ||
| 118 | extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); | ||
| 119 | break; | ||
| 120 | #endif | ||
| 121 | #if !defined(_WIN32) && !defined(__APPLE__) | ||
| 122 | case Core::Frontend::WindowSystemType::X11: | ||
| 123 | extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); | ||
| 124 | break; | ||
| 125 | case Core::Frontend::WindowSystemType::Wayland: | ||
| 126 | extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); | ||
| 127 | break; | ||
| 128 | #endif | ||
| 129 | default: | ||
| 130 | LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | if (window_type != Core::Frontend::WindowSystemType::Headless) { | ||
| 134 | extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); | ||
| 135 | } | ||
| 136 | if (enable_layers) { | ||
| 137 | extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); | ||
| 138 | } | ||
| 139 | extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); | ||
| 140 | |||
| 141 | const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); | ||
| 142 | if (!properties) { | ||
| 143 | LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); | ||
| 144 | return {}; | ||
| 145 | } | ||
| 146 | |||
| 147 | for (const char* extension : extensions) { | ||
| 148 | const auto it = | ||
| 149 | std::find_if(properties->begin(), properties->end(), [extension](const auto& prop) { | ||
| 150 | return !std::strcmp(extension, prop.extensionName); | ||
| 151 | }); | ||
| 152 | if (it == properties->end()) { | ||
| 153 | LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); | ||
| 154 | return {}; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | std::vector<const char*> layers; | ||
| 159 | layers.reserve(1); | ||
| 160 | if (enable_layers) { | ||
| 161 | layers.push_back("VK_LAYER_KHRONOS_validation"); | ||
| 162 | } | ||
| 163 | |||
| 164 | const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld); | ||
| 165 | if (!layer_properties) { | ||
| 166 | LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers"); | ||
| 167 | layers.clear(); | ||
| 168 | } | ||
| 169 | |||
| 170 | for (auto layer_it = layers.begin(); layer_it != layers.end();) { | ||
| 171 | const char* const layer = *layer_it; | ||
| 172 | const auto it = std::find_if( | ||
| 173 | layer_properties->begin(), layer_properties->end(), | ||
| 174 | [layer](const VkLayerProperties& prop) { return !std::strcmp(layer, prop.layerName); }); | ||
| 175 | if (it == layer_properties->end()) { | ||
| 176 | LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer); | ||
| 177 | layer_it = layers.erase(layer_it); | ||
| 178 | } else { | ||
| 179 | ++layer_it; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | vk::Instance instance = vk::Instance::Create(layers, extensions, dld); | ||
| 184 | if (!instance) { | ||
| 185 | LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); | ||
| 186 | return {}; | ||
| 187 | } | ||
| 188 | if (!vk::Load(*instance, dld)) { | ||
| 189 | LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); | ||
| 190 | } | ||
| 191 | return instance; | ||
| 192 | } | ||
| 193 | |||
| 194 | std::string GetReadableVersion(u32 version) { | 40 | std::string GetReadableVersion(u32 version) { |
| 195 | return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), | 41 | return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), |
| 196 | VK_VERSION_PATCH(version)); | 42 | VK_VERSION_PATCH(version)); |
| 197 | } | 43 | } |
| 198 | 44 | ||
| 199 | std::string GetDriverVersion(const VKDevice& device) { | 45 | std::string GetDriverVersion(const Device& device) { |
| 200 | // Extracted from | 46 | // Extracted from |
| 201 | // https://github.com/SaschaWillems/vulkan.gpuinfo.org/blob/5dddea46ea1120b0df14eef8f15ff8e318e35462/functions.php#L308-L314 | 47 | // https://github.com/SaschaWillems/vulkan.gpuinfo.org/blob/5dddea46ea1120b0df14eef8f15ff8e318e35462/functions.php#L308-L314 |
| 202 | const u32 version = device.GetDriverVersion(); | 48 | const u32 version = device.GetDriverVersion(); |
| @@ -213,7 +59,6 @@ std::string GetDriverVersion(const VKDevice& device) { | |||
| 213 | const u32 minor = version & 0x3fff; | 59 | const u32 minor = version & 0x3fff; |
| 214 | return fmt::format("{}.{}", major, minor); | 60 | return fmt::format("{}.{}", major, minor); |
| 215 | } | 61 | } |
| 216 | |||
| 217 | return GetReadableVersion(version); | 62 | return GetReadableVersion(version); |
| 218 | } | 63 | } |
| 219 | 64 | ||
| @@ -240,8 +85,8 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext | |||
| 240 | RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | 85 | RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, |
| 241 | Core::Frontend::EmuWindow& emu_window, | 86 | Core::Frontend::EmuWindow& emu_window, |
| 242 | Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, | 87 | Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, |
| 243 | std::unique_ptr<Core::Frontend::GraphicsContext> context) | 88 | std::unique_ptr<Core::Frontend::GraphicsContext> context_) |
| 244 | : RendererBase{emu_window, std::move(context)}, telemetry_session{telemetry_session_}, | 89 | : RendererBase{emu_window, std::move(context_)}, telemetry_session{telemetry_session_}, |
| 245 | cpu_memory{cpu_memory_}, gpu{gpu_} {} | 90 | cpu_memory{cpu_memory_}, gpu{gpu_} {} |
| 246 | 91 | ||
| 247 | RendererVulkan::~RendererVulkan() { | 92 | RendererVulkan::~RendererVulkan() { |
| @@ -249,12 +94,9 @@ RendererVulkan::~RendererVulkan() { | |||
| 249 | } | 94 | } |
| 250 | 95 | ||
| 251 | void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 96 | void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 252 | render_window.PollEvents(); | ||
| 253 | |||
| 254 | if (!framebuffer) { | 97 | if (!framebuffer) { |
| 255 | return; | 98 | return; |
| 256 | } | 99 | } |
| 257 | |||
| 258 | const auto& layout = render_window.GetFramebufferLayout(); | 100 | const auto& layout = render_window.GetFramebufferLayout(); |
| 259 | if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) { | 101 | if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) { |
| 260 | const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; | 102 | const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; |
| @@ -280,17 +122,19 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 280 | rasterizer->TickFrame(); | 122 | rasterizer->TickFrame(); |
| 281 | } | 123 | } |
| 282 | 124 | ||
| 283 | render_window.PollEvents(); | 125 | render_window.OnFrameDisplayed(); |
| 284 | } | 126 | } |
| 285 | 127 | ||
| 286 | bool RendererVulkan::Init() { | 128 | bool RendererVulkan::Init() try { |
| 287 | library = OpenVulkanLibrary(); | 129 | library = OpenLibrary(); |
| 288 | instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, | 130 | instance = CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, |
| 289 | Settings::values.renderer_debug); | 131 | true, Settings::values.renderer_debug); |
| 290 | if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { | 132 | if (Settings::values.renderer_debug) { |
| 291 | return false; | 133 | debug_callback = CreateDebugCallback(instance); |
| 292 | } | 134 | } |
| 135 | surface = CreateSurface(instance, render_window); | ||
| 293 | 136 | ||
| 137 | InitializeDevice(); | ||
| 294 | Report(); | 138 | Report(); |
| 295 | 139 | ||
| 296 | memory_manager = std::make_unique<VKMemoryManager>(*device); | 140 | memory_manager = std::make_unique<VKMemoryManager>(*device); |
| @@ -310,8 +154,11 @@ bool RendererVulkan::Init() { | |||
| 310 | blit_screen = | 154 | blit_screen = |
| 311 | std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, | 155 | std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, |
| 312 | *memory_manager, *swapchain, *scheduler, screen_info); | 156 | *memory_manager, *swapchain, *scheduler, screen_info); |
| 313 | |||
| 314 | return true; | 157 | return true; |
| 158 | |||
| 159 | } catch (const vk::Exception& exception) { | ||
| 160 | LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what()); | ||
| 161 | return false; | ||
| 315 | } | 162 | } |
| 316 | 163 | ||
| 317 | void RendererVulkan::ShutDown() { | 164 | void RendererVulkan::ShutDown() { |
| @@ -321,7 +168,6 @@ void RendererVulkan::ShutDown() { | |||
| 321 | if (const auto& dev = device->GetLogical()) { | 168 | if (const auto& dev = device->GetLogical()) { |
| 322 | dev.WaitIdle(); | 169 | dev.WaitIdle(); |
| 323 | } | 170 | } |
| 324 | |||
| 325 | rasterizer.reset(); | 171 | rasterizer.reset(); |
| 326 | blit_screen.reset(); | 172 | blit_screen.reset(); |
| 327 | scheduler.reset(); | 173 | scheduler.reset(); |
| @@ -330,94 +176,15 @@ void RendererVulkan::ShutDown() { | |||
| 330 | device.reset(); | 176 | device.reset(); |
| 331 | } | 177 | } |
| 332 | 178 | ||
| 333 | bool RendererVulkan::CreateDebugCallback() { | 179 | void RendererVulkan::InitializeDevice() { |
| 334 | if (!Settings::values.renderer_debug) { | 180 | const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices(); |
| 335 | return true; | ||
| 336 | } | ||
| 337 | debug_callback = instance.TryCreateDebugCallback(DebugCallback); | ||
| 338 | if (!debug_callback) { | ||
| 339 | LOG_ERROR(Render_Vulkan, "Failed to create debug callback"); | ||
| 340 | return false; | ||
| 341 | } | ||
| 342 | return true; | ||
| 343 | } | ||
| 344 | |||
| 345 | bool RendererVulkan::CreateSurface() { | ||
| 346 | [[maybe_unused]] const auto& window_info = render_window.GetWindowInfo(); | ||
| 347 | VkSurfaceKHR unsafe_surface = nullptr; | ||
| 348 | |||
| 349 | #ifdef _WIN32 | ||
| 350 | if (window_info.type == Core::Frontend::WindowSystemType::Windows) { | ||
| 351 | const HWND hWnd = static_cast<HWND>(window_info.render_surface); | ||
| 352 | const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, | ||
| 353 | nullptr, 0, nullptr, hWnd}; | ||
| 354 | const auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>( | ||
| 355 | dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR")); | ||
| 356 | if (!vkCreateWin32SurfaceKHR || | ||
| 357 | vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { | ||
| 358 | LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface"); | ||
| 359 | return false; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | #endif | ||
| 363 | #if !defined(_WIN32) && !defined(__APPLE__) | ||
| 364 | if (window_info.type == Core::Frontend::WindowSystemType::X11) { | ||
| 365 | const VkXlibSurfaceCreateInfoKHR xlib_ci{ | ||
| 366 | VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, | ||
| 367 | static_cast<Display*>(window_info.display_connection), | ||
| 368 | reinterpret_cast<Window>(window_info.render_surface)}; | ||
| 369 | const auto vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>( | ||
| 370 | dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR")); | ||
| 371 | if (!vkCreateXlibSurfaceKHR || | ||
| 372 | vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { | ||
| 373 | LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface"); | ||
| 374 | return false; | ||
| 375 | } | ||
| 376 | } | ||
| 377 | if (window_info.type == Core::Frontend::WindowSystemType::Wayland) { | ||
| 378 | const VkWaylandSurfaceCreateInfoKHR wayland_ci{ | ||
| 379 | VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0, | ||
| 380 | static_cast<wl_display*>(window_info.display_connection), | ||
| 381 | static_cast<wl_surface*>(window_info.render_surface)}; | ||
| 382 | const auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>( | ||
| 383 | dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR")); | ||
| 384 | if (!vkCreateWaylandSurfaceKHR || | ||
| 385 | vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) != | ||
| 386 | VK_SUCCESS) { | ||
| 387 | LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface"); | ||
| 388 | return false; | ||
| 389 | } | ||
| 390 | } | ||
| 391 | #endif | ||
| 392 | if (!unsafe_surface) { | ||
| 393 | LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); | ||
| 394 | return false; | ||
| 395 | } | ||
| 396 | |||
| 397 | surface = vk::SurfaceKHR(unsafe_surface, *instance, dld); | ||
| 398 | return true; | ||
| 399 | } | ||
| 400 | |||
| 401 | bool RendererVulkan::PickDevices() { | ||
| 402 | const auto devices = instance.EnumeratePhysicalDevices(); | ||
| 403 | if (!devices) { | ||
| 404 | LOG_ERROR(Render_Vulkan, "Failed to enumerate physical devices"); | ||
| 405 | return false; | ||
| 406 | } | ||
| 407 | |||
| 408 | const s32 device_index = Settings::values.vulkan_device.GetValue(); | 181 | const s32 device_index = Settings::values.vulkan_device.GetValue(); |
| 409 | if (device_index < 0 || device_index >= static_cast<s32>(devices->size())) { | 182 | if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) { |
| 410 | LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); | 183 | LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); |
| 411 | return false; | 184 | throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
| 412 | } | ||
| 413 | const vk::PhysicalDevice physical_device((*devices)[static_cast<std::size_t>(device_index)], | ||
| 414 | dld); | ||
| 415 | if (!VKDevice::IsSuitable(physical_device, *surface)) { | ||
| 416 | return false; | ||
| 417 | } | 185 | } |
| 418 | 186 | const vk::PhysicalDevice physical_device(devices[static_cast<size_t>(device_index)], dld); | |
| 419 | device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld); | 187 | device = std::make_unique<Device>(*instance, physical_device, *surface, dld); |
| 420 | return device->Create(); | ||
| 421 | } | 188 | } |
| 422 | 189 | ||
| 423 | void RendererVulkan::Report() const { | 190 | void RendererVulkan::Report() const { |
| @@ -426,7 +193,7 @@ void RendererVulkan::Report() const { | |||
| 426 | const std::string driver_version = GetDriverVersion(*device); | 193 | const std::string driver_version = GetDriverVersion(*device); |
| 427 | const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version); | 194 | const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version); |
| 428 | 195 | ||
| 429 | const std::string api_version = GetReadableVersion(device->GetApiVersion()); | 196 | const std::string api_version = GetReadableVersion(device->ApiVersion()); |
| 430 | 197 | ||
| 431 | const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions()); | 198 | const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions()); |
| 432 | 199 | ||
| @@ -442,25 +209,21 @@ void RendererVulkan::Report() const { | |||
| 442 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); | 209 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); |
| 443 | } | 210 | } |
| 444 | 211 | ||
| 445 | std::vector<std::string> RendererVulkan::EnumerateDevices() { | 212 | std::vector<std::string> RendererVulkan::EnumerateDevices() try { |
| 446 | vk::InstanceDispatch dld; | 213 | vk::InstanceDispatch dld; |
| 447 | Common::DynamicLibrary library = OpenVulkanLibrary(); | 214 | const Common::DynamicLibrary library = OpenLibrary(); |
| 448 | vk::Instance instance = CreateInstance(library, dld); | 215 | const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0); |
| 449 | if (!instance) { | 216 | const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices(); |
| 450 | return {}; | ||
| 451 | } | ||
| 452 | |||
| 453 | const std::optional physical_devices = instance.EnumeratePhysicalDevices(); | ||
| 454 | if (!physical_devices) { | ||
| 455 | return {}; | ||
| 456 | } | ||
| 457 | |||
| 458 | std::vector<std::string> names; | 217 | std::vector<std::string> names; |
| 459 | names.reserve(physical_devices->size()); | 218 | names.reserve(physical_devices.size()); |
| 460 | for (const auto& device : *physical_devices) { | 219 | for (const VkPhysicalDevice device : physical_devices) { |
| 461 | names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName); | 220 | names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName); |
| 462 | } | 221 | } |
| 463 | return names; | 222 | return names; |
| 223 | |||
| 224 | } catch (const vk::Exception& exception) { | ||
| 225 | LOG_ERROR(Render_Vulkan, "Failed to enumerate devices with error: {}", exception.what()); | ||
| 226 | return {}; | ||
| 464 | } | 227 | } |
| 465 | 228 | ||
| 466 | } // namespace Vulkan | 229 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 49a4141ec..5575ffc54 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #include "common/dynamic_library.h" | 11 | #include "common/dynamic_library.h" |
| 12 | 12 | ||
| 13 | #include "video_core/renderer_base.h" | 13 | #include "video_core/renderer_base.h" |
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 15 | 15 | ||
| 16 | namespace Core { | 16 | namespace Core { |
| 17 | class TelemetrySession; | 17 | class TelemetrySession; |
| @@ -27,16 +27,15 @@ class GPU; | |||
| 27 | 27 | ||
| 28 | namespace Vulkan { | 28 | namespace Vulkan { |
| 29 | 29 | ||
| 30 | class Device; | ||
| 30 | class StateTracker; | 31 | class StateTracker; |
| 31 | class VKBlitScreen; | 32 | class VKBlitScreen; |
| 32 | class VKDevice; | ||
| 33 | class VKMemoryManager; | 33 | class VKMemoryManager; |
| 34 | class VKSwapchain; | 34 | class VKSwapchain; |
| 35 | class VKScheduler; | 35 | class VKScheduler; |
| 36 | class VKImage; | ||
| 37 | 36 | ||
| 38 | struct VKScreenInfo { | 37 | struct VKScreenInfo { |
| 39 | VKImage* image{}; | 38 | VkImageView image_view{}; |
| 40 | u32 width{}; | 39 | u32 width{}; |
| 41 | u32 height{}; | 40 | u32 height{}; |
| 42 | bool is_srgb{}; | 41 | bool is_srgb{}; |
| @@ -45,9 +44,9 @@ struct VKScreenInfo { | |||
| 45 | class RendererVulkan final : public VideoCore::RendererBase { | 44 | class RendererVulkan final : public VideoCore::RendererBase { |
| 46 | public: | 45 | public: |
| 47 | explicit RendererVulkan(Core::TelemetrySession& telemtry_session, | 46 | explicit RendererVulkan(Core::TelemetrySession& telemtry_session, |
| 48 | Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory, | 47 | Core::Frontend::EmuWindow& emu_window, |
| 49 | Tegra::GPU& gpu, | 48 | Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, |
| 50 | std::unique_ptr<Core::Frontend::GraphicsContext> context); | 49 | std::unique_ptr<Core::Frontend::GraphicsContext> context_); |
| 51 | ~RendererVulkan() override; | 50 | ~RendererVulkan() override; |
| 52 | 51 | ||
| 53 | bool Init() override; | 52 | bool Init() override; |
| @@ -57,11 +56,7 @@ public: | |||
| 57 | static std::vector<std::string> EnumerateDevices(); | 56 | static std::vector<std::string> EnumerateDevices(); |
| 58 | 57 | ||
| 59 | private: | 58 | private: |
| 60 | bool CreateDebugCallback(); | 59 | void InitializeDevice(); |
| 61 | |||
| 62 | bool CreateSurface(); | ||
| 63 | |||
| 64 | bool PickDevices(); | ||
| 65 | 60 | ||
| 66 | void Report() const; | 61 | void Report() const; |
| 67 | 62 | ||
| @@ -73,12 +68,13 @@ private: | |||
| 73 | vk::InstanceDispatch dld; | 68 | vk::InstanceDispatch dld; |
| 74 | 69 | ||
| 75 | vk::Instance instance; | 70 | vk::Instance instance; |
| 71 | |||
| 76 | vk::SurfaceKHR surface; | 72 | vk::SurfaceKHR surface; |
| 77 | 73 | ||
| 78 | VKScreenInfo screen_info; | 74 | VKScreenInfo screen_info; |
| 79 | 75 | ||
| 80 | vk::DebugCallback debug_callback; | 76 | vk::DebugUtilsMessenger debug_callback; |
| 81 | std::unique_ptr<VKDevice> device; | 77 | std::unique_ptr<Device> device; |
| 82 | std::unique_ptr<VKMemoryManager> memory_manager; | 78 | std::unique_ptr<VKMemoryManager> memory_manager; |
| 83 | std::unique_ptr<StateTracker> state_tracker; | 79 | std::unique_ptr<StateTracker> state_tracker; |
| 84 | std::unique_ptr<VKScheduler> scheduler; | 80 | std::unique_ptr<VKScheduler> scheduler; |
diff --git a/src/video_core/renderer_vulkan/shaders/blit.frag b/src/video_core/renderer_vulkan/shaders/blit.frag deleted file mode 100644 index a06ecd24a..000000000 --- a/src/video_core/renderer_vulkan/shaders/blit.frag +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Build instructions: | ||
| 7 | * $ glslangValidator -V $THIS_FILE -o output.spv | ||
| 8 | * $ spirv-opt -O --strip-debug output.spv -o optimized.spv | ||
| 9 | * $ xxd -i optimized.spv | ||
| 10 | * | ||
| 11 | * Then copy that bytecode to the C++ file | ||
| 12 | */ | ||
| 13 | |||
| 14 | #version 460 core | ||
| 15 | |||
| 16 | layout (location = 0) in vec2 frag_tex_coord; | ||
| 17 | |||
| 18 | layout (location = 0) out vec4 color; | ||
| 19 | |||
| 20 | layout (binding = 1) uniform sampler2D color_texture; | ||
| 21 | |||
| 22 | void main() { | ||
| 23 | color = texture(color_texture, frag_tex_coord); | ||
| 24 | } | ||
diff --git a/src/video_core/renderer_vulkan/shaders/blit.vert b/src/video_core/renderer_vulkan/shaders/blit.vert deleted file mode 100644 index c64d9235a..000000000 --- a/src/video_core/renderer_vulkan/shaders/blit.vert +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Build instructions: | ||
| 7 | * $ glslangValidator -V $THIS_FILE -o output.spv | ||
| 8 | * $ spirv-opt -O --strip-debug output.spv -o optimized.spv | ||
| 9 | * $ xxd -i optimized.spv | ||
| 10 | * | ||
| 11 | * Then copy that bytecode to the C++ file | ||
| 12 | */ | ||
| 13 | |||
| 14 | #version 460 core | ||
| 15 | |||
| 16 | layout (location = 0) in vec2 vert_position; | ||
| 17 | layout (location = 1) in vec2 vert_tex_coord; | ||
| 18 | |||
| 19 | layout (location = 0) out vec2 frag_tex_coord; | ||
| 20 | |||
| 21 | layout (set = 0, binding = 0) uniform MatrixBlock { | ||
| 22 | mat4 modelview_matrix; | ||
| 23 | }; | ||
| 24 | |||
| 25 | void main() { | ||
| 26 | gl_Position = modelview_matrix * vec4(vert_position, 0.0, 1.0); | ||
| 27 | frag_tex_coord = vert_tex_coord; | ||
| 28 | } | ||
diff --git a/src/video_core/renderer_vulkan/shaders/quad_array.comp b/src/video_core/renderer_vulkan/shaders/quad_array.comp deleted file mode 100644 index 5a5703308..000000000 --- a/src/video_core/renderer_vulkan/shaders/quad_array.comp +++ /dev/null | |||
| @@ -1,37 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Build instructions: | ||
| 7 | * $ glslangValidator -V $THIS_FILE -o output.spv | ||
| 8 | * $ spirv-opt -O --strip-debug output.spv -o optimized.spv | ||
| 9 | * $ xxd -i optimized.spv | ||
| 10 | * | ||
| 11 | * Then copy that bytecode to the C++ file | ||
| 12 | */ | ||
| 13 | |||
| 14 | #version 460 core | ||
| 15 | |||
| 16 | layout (local_size_x = 1024) in; | ||
| 17 | |||
| 18 | layout (std430, set = 0, binding = 0) buffer OutputBuffer { | ||
| 19 | uint output_indexes[]; | ||
| 20 | }; | ||
| 21 | |||
| 22 | layout (push_constant) uniform PushConstants { | ||
| 23 | uint first; | ||
| 24 | }; | ||
| 25 | |||
| 26 | void main() { | ||
| 27 | uint primitive = gl_GlobalInvocationID.x; | ||
| 28 | if (primitive * 6 >= output_indexes.length()) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | const uint quad_map[6] = uint[](0, 1, 2, 0, 2, 3); | ||
| 33 | for (uint vertex = 0; vertex < 6; ++vertex) { | ||
| 34 | uint index = first + primitive * 4 + quad_map[vertex]; | ||
| 35 | output_indexes[primitive * 6 + vertex] = index; | ||
| 36 | } | ||
| 37 | } | ||
diff --git a/src/video_core/renderer_vulkan/shaders/quad_indexed.comp b/src/video_core/renderer_vulkan/shaders/quad_indexed.comp deleted file mode 100644 index 5a472ba9b..000000000 --- a/src/video_core/renderer_vulkan/shaders/quad_indexed.comp +++ /dev/null | |||
| @@ -1,50 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Build instructions: | ||
| 7 | * $ glslangValidator -V quad_indexed.comp -o output.spv | ||
| 8 | * $ spirv-opt -O --strip-debug output.spv -o optimized.spv | ||
| 9 | * $ xxd -i optimized.spv | ||
| 10 | * | ||
| 11 | * Then copy that bytecode to the C++ file | ||
| 12 | */ | ||
| 13 | |||
| 14 | #version 460 core | ||
| 15 | |||
| 16 | layout (local_size_x = 1024) in; | ||
| 17 | |||
| 18 | layout (std430, set = 0, binding = 0) readonly buffer InputBuffer { | ||
| 19 | uint input_indexes[]; | ||
| 20 | }; | ||
| 21 | |||
| 22 | layout (std430, set = 0, binding = 1) writeonly buffer OutputBuffer { | ||
| 23 | uint output_indexes[]; | ||
| 24 | }; | ||
| 25 | |||
| 26 | layout (push_constant) uniform PushConstants { | ||
| 27 | uint base_vertex; | ||
| 28 | int index_shift; // 0: uint8, 1: uint16, 2: uint32 | ||
| 29 | }; | ||
| 30 | |||
| 31 | void main() { | ||
| 32 | int primitive = int(gl_GlobalInvocationID.x); | ||
| 33 | if (primitive * 6 >= output_indexes.length()) { | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | |||
| 37 | int index_size = 8 << index_shift; | ||
| 38 | int flipped_shift = 2 - index_shift; | ||
| 39 | int mask = (1 << flipped_shift) - 1; | ||
| 40 | |||
| 41 | const int quad_swizzle[6] = int[](0, 1, 2, 0, 2, 3); | ||
| 42 | for (uint vertex = 0; vertex < 6; ++vertex) { | ||
| 43 | int offset = primitive * 4 + quad_swizzle[vertex]; | ||
| 44 | int int_offset = offset >> flipped_shift; | ||
| 45 | int bit_offset = (offset & mask) * index_size; | ||
| 46 | uint packed_input = input_indexes[int_offset]; | ||
| 47 | uint index = bitfieldExtract(packed_input, bit_offset, index_size); | ||
| 48 | output_indexes[primitive * 6 + vertex] = index + base_vertex; | ||
| 49 | } | ||
| 50 | } | ||
diff --git a/src/video_core/renderer_vulkan/shaders/uint8.comp b/src/video_core/renderer_vulkan/shaders/uint8.comp deleted file mode 100644 index a320f3ae0..000000000 --- a/src/video_core/renderer_vulkan/shaders/uint8.comp +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Build instructions: | ||
| 7 | * $ glslangValidator -V $THIS_FILE -o output.spv | ||
| 8 | * $ spirv-opt -O --strip-debug output.spv -o optimized.spv | ||
| 9 | * $ xxd -i optimized.spv | ||
| 10 | * | ||
| 11 | * Then copy that bytecode to the C++ file | ||
| 12 | */ | ||
| 13 | |||
| 14 | #version 460 core | ||
| 15 | #extension GL_EXT_shader_16bit_storage : require | ||
| 16 | #extension GL_EXT_shader_8bit_storage : require | ||
| 17 | |||
| 18 | layout (local_size_x = 1024) in; | ||
| 19 | |||
| 20 | layout (std430, set = 0, binding = 0) readonly buffer InputBuffer { | ||
| 21 | uint8_t input_indexes[]; | ||
| 22 | }; | ||
| 23 | |||
| 24 | layout (std430, set = 0, binding = 1) writeonly buffer OutputBuffer { | ||
| 25 | uint16_t output_indexes[]; | ||
| 26 | }; | ||
| 27 | |||
| 28 | void main() { | ||
| 29 | uint id = gl_GlobalInvocationID.x; | ||
| 30 | if (id < input_indexes.length()) { | ||
| 31 | output_indexes[id] = uint16_t(input_indexes[id]); | ||
| 32 | } | ||
| 33 | } | ||
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index b5b60309e..5e184eb42 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -16,121 +16,25 @@ | |||
| 16 | #include "core/frontend/emu_window.h" | 16 | #include "core/frontend/emu_window.h" |
| 17 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 18 | #include "video_core/gpu.h" | 18 | #include "video_core/gpu.h" |
| 19 | #include "video_core/morton.h" | 19 | #include "video_core/host_shaders/vulkan_present_frag_spv.h" |
| 20 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" | ||
| 20 | #include "video_core/rasterizer_interface.h" | 21 | #include "video_core/rasterizer_interface.h" |
| 21 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 22 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 22 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 23 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 23 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 24 | #include "video_core/renderer_vulkan/vk_image.h" | ||
| 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 24 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 26 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 25 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 26 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 28 | #include "video_core/renderer_vulkan/vk_shader_util.h" | 27 | #include "video_core/renderer_vulkan/vk_shader_util.h" |
| 29 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 28 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 30 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 31 | #include "video_core/surface.h" | 29 | #include "video_core/surface.h" |
| 30 | #include "video_core/textures/decoders.h" | ||
| 31 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 32 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 32 | 33 | ||
| 33 | namespace Vulkan { | 34 | namespace Vulkan { |
| 34 | 35 | ||
| 35 | namespace { | 36 | namespace { |
| 36 | 37 | ||
| 37 | // Generated from the "shaders/" directory, read the instructions there. | ||
| 38 | constexpr u8 blit_vertex_code[] = { | ||
| 39 | 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x27, 0x00, 0x00, 0x00, | ||
| 40 | 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, | ||
| 41 | 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, | ||
| 42 | 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 43 | 0x0f, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, | ||
| 44 | 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | ||
| 45 | 0x25, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 46 | 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 47 | 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, | ||
| 48 | 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 49 | 0x48, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 50 | 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 51 | 0x48, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 52 | 0x48, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 53 | 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 54 | 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 55 | 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 56 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 57 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | ||
| 58 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | ||
| 59 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | ||
| 60 | 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, | ||
| 61 | 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 62 | 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 63 | 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 64 | 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 65 | 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 66 | 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 67 | 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, | ||
| 68 | 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, | ||
| 69 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, | ||
| 70 | 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, | ||
| 71 | 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, | ||
| 72 | 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, | ||
| 73 | 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 74 | 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 75 | 0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 76 | 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, | ||
| 77 | 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 78 | 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 79 | 0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 80 | 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 81 | 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 82 | 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 83 | 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 84 | 0x24, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 85 | 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 86 | 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, | ||
| 87 | 0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 88 | 0x13, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 89 | 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, | ||
| 90 | 0x1a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 91 | 0x1d, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, | ||
| 92 | 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 93 | 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 94 | 0x1e, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, | ||
| 95 | 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, | ||
| 96 | 0x41, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 97 | 0x0f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 98 | 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | ||
| 99 | 0x3e, 0x00, 0x03, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, | ||
| 100 | 0x38, 0x00, 0x01, 0x00}; | ||
| 101 | |||
| 102 | constexpr u8 blit_fragment_code[] = { | ||
| 103 | 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 104 | 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, | ||
| 105 | 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, | ||
| 106 | 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 107 | 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, | ||
| 108 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, | ||
| 109 | 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 110 | 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 111 | 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 112 | 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 113 | 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 114 | 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, | ||
| 115 | 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 116 | 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 117 | 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 118 | 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 119 | 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 120 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, | ||
| 121 | 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 122 | 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 123 | 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 124 | 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 125 | 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 126 | 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 127 | 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, | ||
| 128 | 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 129 | 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 130 | 0x11, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 131 | 0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 132 | 0x13, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; | ||
| 133 | |||
| 134 | struct ScreenRectVertex { | 38 | struct ScreenRectVertex { |
| 135 | ScreenRectVertex() = default; | 39 | ScreenRectVertex() = default; |
| 136 | explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} | 40 | explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} |
| @@ -173,9 +77,9 @@ constexpr std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | |||
| 173 | // clang-format on | 77 | // clang-format on |
| 174 | } | 78 | } |
| 175 | 79 | ||
| 176 | std::size_t GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { | 80 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { |
| 177 | using namespace VideoCore::Surface; | 81 | using namespace VideoCore::Surface; |
| 178 | return GetBytesPerPixel(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); | 82 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); |
| 179 | } | 83 | } |
| 180 | 84 | ||
| 181 | std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { | 85 | std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -210,7 +114,7 @@ struct VKBlitScreen::BufferData { | |||
| 210 | 114 | ||
| 211 | VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, | 115 | VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, |
| 212 | Core::Frontend::EmuWindow& render_window_, | 116 | Core::Frontend::EmuWindow& render_window_, |
| 213 | VideoCore::RasterizerInterface& rasterizer_, const VKDevice& device_, | 117 | VideoCore::RasterizerInterface& rasterizer_, const Device& device_, |
| 214 | VKMemoryManager& memory_manager_, VKSwapchain& swapchain_, | 118 | VKMemoryManager& memory_manager_, VKSwapchain& swapchain_, |
| 215 | VKScheduler& scheduler_, const VKScreenInfo& screen_info_) | 119 | VKScheduler& scheduler_, const VKScreenInfo& screen_info_) |
| 216 | : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, | 120 | : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, |
| @@ -239,34 +143,30 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 239 | scheduler.Wait(resource_ticks[image_index]); | 143 | scheduler.Wait(resource_ticks[image_index]); |
| 240 | resource_ticks[image_index] = scheduler.CurrentTick(); | 144 | resource_ticks[image_index] = scheduler.CurrentTick(); |
| 241 | 145 | ||
| 242 | VKImage* blit_image = use_accelerated ? screen_info.image : raw_images[image_index].get(); | 146 | UpdateDescriptorSet(image_index, |
| 243 | 147 | use_accelerated ? screen_info.image_view : *raw_image_views[image_index]); | |
| 244 | UpdateDescriptorSet(image_index, blit_image->GetPresentView()); | ||
| 245 | 148 | ||
| 246 | BufferData data; | 149 | BufferData data; |
| 247 | SetUniformData(data, framebuffer); | 150 | SetUniformData(data, framebuffer); |
| 248 | SetVertexData(data, framebuffer); | 151 | SetVertexData(data, framebuffer); |
| 249 | 152 | ||
| 250 | auto map = buffer_commit->Map(); | 153 | auto map = buffer_commit->Map(); |
| 251 | std::memcpy(map.GetAddress(), &data, sizeof(data)); | 154 | std::memcpy(map.Address(), &data, sizeof(data)); |
| 252 | 155 | ||
| 253 | if (!use_accelerated) { | 156 | if (!use_accelerated) { |
| 254 | const u64 image_offset = GetRawImageOffset(framebuffer, image_index); | 157 | const u64 image_offset = GetRawImageOffset(framebuffer, image_index); |
| 255 | 158 | ||
| 256 | const auto pixel_format = | ||
| 257 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format); | ||
| 258 | const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset; | 159 | const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset; |
| 259 | const auto host_ptr = cpu_memory.GetPointer(framebuffer_addr); | 160 | const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr); |
| 260 | rasterizer.FlushRegion(ToCacheAddr(host_ptr), GetSizeInBytes(framebuffer)); | 161 | const size_t size_bytes = GetSizeInBytes(framebuffer); |
| 162 | rasterizer.FlushRegion(ToCacheAddr(host_ptr), size_bytes); | ||
| 261 | 163 | ||
| 262 | // TODO(Rodrigo): Read this from HLE | 164 | // TODO(Rodrigo): Read this from HLE |
| 263 | constexpr u32 block_height_log2 = 4; | 165 | constexpr u32 block_height_log2 = 4; |
| 264 | VideoCore::MortonSwizzle(VideoCore::MortonSwizzleMode::MortonToLinear, pixel_format, | 166 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); |
| 265 | framebuffer.stride, block_height_log2, framebuffer.height, 0, 1, 1, | 167 | Tegra::Texture::UnswizzleTexture( |
| 266 | map.GetAddress() + image_offset, host_ptr); | 168 | std::span(map.Address() + image_offset, size_bytes), std::span(host_ptr, size_bytes), |
| 267 | 169 | bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); | |
| 268 | blit_image->Transition(0, 1, 0, 1, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 269 | VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | ||
| 270 | 170 | ||
| 271 | const VkBufferImageCopy copy{ | 171 | const VkBufferImageCopy copy{ |
| 272 | .bufferOffset = image_offset, | 172 | .bufferOffset = image_offset, |
| @@ -288,15 +188,44 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 288 | }, | 188 | }, |
| 289 | }; | 189 | }; |
| 290 | scheduler.Record( | 190 | scheduler.Record( |
| 291 | [buffer = *buffer, image = *blit_image->GetHandle(), copy](vk::CommandBuffer cmdbuf) { | 191 | [buffer = *buffer, image = *raw_images[image_index], copy](vk::CommandBuffer cmdbuf) { |
| 292 | cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); | 192 | const VkImageMemoryBarrier base_barrier{ |
| 193 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 194 | .pNext = nullptr, | ||
| 195 | .srcAccessMask = 0, | ||
| 196 | .dstAccessMask = 0, | ||
| 197 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 198 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 199 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 200 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 201 | .image = image, | ||
| 202 | .subresourceRange = | ||
| 203 | { | ||
| 204 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 205 | .baseMipLevel = 0, | ||
| 206 | .levelCount = 1, | ||
| 207 | .baseArrayLayer = 0, | ||
| 208 | .layerCount = 1, | ||
| 209 | }, | ||
| 210 | }; | ||
| 211 | VkImageMemoryBarrier read_barrier = base_barrier; | ||
| 212 | read_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; | ||
| 213 | read_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 214 | read_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 215 | |||
| 216 | VkImageMemoryBarrier write_barrier = base_barrier; | ||
| 217 | write_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 218 | write_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 219 | |||
| 220 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 221 | 0, read_barrier); | ||
| 222 | cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_GENERAL, copy); | ||
| 223 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 224 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); | ||
| 293 | }); | 225 | }); |
| 294 | } | 226 | } |
| 295 | map.Release(); | 227 | map.Release(); |
| 296 | 228 | ||
| 297 | blit_image->Transition(0, 1, 0, 1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, | ||
| 298 | VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | ||
| 299 | |||
| 300 | scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], | 229 | scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], |
| 301 | descriptor_set = descriptor_sets[image_index], buffer = *buffer, | 230 | descriptor_set = descriptor_sets[image_index], buffer = *buffer, |
| 302 | size = swapchain.GetSize(), pipeline = *pipeline, | 231 | size = swapchain.GetSize(), pipeline = *pipeline, |
| @@ -304,31 +233,31 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 304 | const VkClearValue clear_color{ | 233 | const VkClearValue clear_color{ |
| 305 | .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}}, | 234 | .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}}, |
| 306 | }; | 235 | }; |
| 307 | 236 | const VkRenderPassBeginInfo renderpass_bi{ | |
| 308 | VkRenderPassBeginInfo renderpass_bi; | 237 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, |
| 309 | renderpass_bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | 238 | .pNext = nullptr, |
| 310 | renderpass_bi.pNext = nullptr; | 239 | .renderPass = renderpass, |
| 311 | renderpass_bi.renderPass = renderpass; | 240 | .framebuffer = framebuffer, |
| 312 | renderpass_bi.framebuffer = framebuffer; | 241 | .renderArea = |
| 313 | renderpass_bi.renderArea.offset.x = 0; | 242 | { |
| 314 | renderpass_bi.renderArea.offset.y = 0; | 243 | .offset = {0, 0}, |
| 315 | renderpass_bi.renderArea.extent = size; | 244 | .extent = size, |
| 316 | renderpass_bi.clearValueCount = 1; | 245 | }, |
| 317 | renderpass_bi.pClearValues = &clear_color; | 246 | .clearValueCount = 1, |
| 318 | 247 | .pClearValues = &clear_color, | |
| 319 | VkViewport viewport; | 248 | }; |
| 320 | viewport.x = 0.0f; | 249 | const VkViewport viewport{ |
| 321 | viewport.y = 0.0f; | 250 | .x = 0.0f, |
| 322 | viewport.width = static_cast<float>(size.width); | 251 | .y = 0.0f, |
| 323 | viewport.height = static_cast<float>(size.height); | 252 | .width = static_cast<float>(size.width), |
| 324 | viewport.minDepth = 0.0f; | 253 | .height = static_cast<float>(size.height), |
| 325 | viewport.maxDepth = 1.0f; | 254 | .minDepth = 0.0f, |
| 326 | 255 | .maxDepth = 1.0f, | |
| 327 | VkRect2D scissor; | 256 | }; |
| 328 | scissor.offset.x = 0; | 257 | const VkRect2D scissor{ |
| 329 | scissor.offset.y = 0; | 258 | .offset = {0, 0}, |
| 330 | scissor.extent = size; | 259 | .extent = size, |
| 331 | 260 | }; | |
| 332 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | 261 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); |
| 333 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | 262 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); |
| 334 | cmdbuf.SetViewport(0, viewport); | 263 | cmdbuf.SetViewport(0, viewport); |
| @@ -372,8 +301,8 @@ void VKBlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) | |||
| 372 | } | 301 | } |
| 373 | 302 | ||
| 374 | void VKBlitScreen::CreateShaders() { | 303 | void VKBlitScreen::CreateShaders() { |
| 375 | vertex_shader = BuildShader(device, sizeof(blit_vertex_code), blit_vertex_code); | 304 | vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); |
| 376 | fragment_shader = BuildShader(device, sizeof(blit_fragment_code), blit_fragment_code); | 305 | fragment_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV); |
| 377 | } | 306 | } |
| 378 | 307 | ||
| 379 | void VKBlitScreen::CreateSemaphores() { | 308 | void VKBlitScreen::CreateSemaphores() { |
| @@ -420,7 +349,7 @@ void VKBlitScreen::CreateRenderPass() { | |||
| 420 | 349 | ||
| 421 | const VkAttachmentReference color_attachment_ref{ | 350 | const VkAttachmentReference color_attachment_ref{ |
| 422 | .attachment = 0, | 351 | .attachment = 0, |
| 423 | .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, | 352 | .layout = VK_IMAGE_LAYOUT_GENERAL, |
| 424 | }; | 353 | }; |
| 425 | 354 | ||
| 426 | const VkSubpassDescription subpass_description{ | 355 | const VkSubpassDescription subpass_description{ |
| @@ -735,34 +664,56 @@ void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuff | |||
| 735 | 664 | ||
| 736 | void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | 665 | void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { |
| 737 | raw_images.resize(image_count); | 666 | raw_images.resize(image_count); |
| 667 | raw_image_views.resize(image_count); | ||
| 738 | raw_buffer_commits.resize(image_count); | 668 | raw_buffer_commits.resize(image_count); |
| 739 | 669 | ||
| 740 | const VkImageCreateInfo ci{ | 670 | for (size_t i = 0; i < image_count; ++i) { |
| 741 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 671 | raw_images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{ |
| 742 | .pNext = nullptr, | 672 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 743 | .flags = 0, | 673 | .pNext = nullptr, |
| 744 | .imageType = VK_IMAGE_TYPE_2D, | 674 | .flags = 0, |
| 745 | .format = GetFormat(framebuffer), | 675 | .imageType = VK_IMAGE_TYPE_2D, |
| 746 | .extent = | 676 | .format = GetFormat(framebuffer), |
| 747 | { | 677 | .extent = |
| 748 | .width = framebuffer.width, | 678 | { |
| 749 | .height = framebuffer.height, | 679 | .width = framebuffer.width, |
| 750 | .depth = 1, | 680 | .height = framebuffer.height, |
| 751 | }, | 681 | .depth = 1, |
| 752 | .mipLevels = 1, | 682 | }, |
| 753 | .arrayLayers = 1, | 683 | .mipLevels = 1, |
| 754 | .samples = VK_SAMPLE_COUNT_1_BIT, | 684 | .arrayLayers = 1, |
| 755 | .tiling = VK_IMAGE_TILING_LINEAR, | 685 | .samples = VK_SAMPLE_COUNT_1_BIT, |
| 756 | .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, | 686 | .tiling = VK_IMAGE_TILING_LINEAR, |
| 757 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 687 | .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, |
| 758 | .queueFamilyIndexCount = 0, | 688 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 759 | .pQueueFamilyIndices = nullptr, | 689 | .queueFamilyIndexCount = 0, |
| 760 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 690 | .pQueueFamilyIndices = nullptr, |
| 761 | }; | 691 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 762 | 692 | }); | |
| 763 | for (std::size_t i = 0; i < image_count; ++i) { | 693 | raw_buffer_commits[i] = memory_manager.Commit(raw_images[i], false); |
| 764 | raw_images[i] = std::make_unique<VKImage>(device, scheduler, ci, VK_IMAGE_ASPECT_COLOR_BIT); | 694 | raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 765 | raw_buffer_commits[i] = memory_manager.Commit(raw_images[i]->GetHandle(), false); | 695 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 696 | .pNext = nullptr, | ||
| 697 | .flags = 0, | ||
| 698 | .image = *raw_images[i], | ||
| 699 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 700 | .format = GetFormat(framebuffer), | ||
| 701 | .components = | ||
| 702 | { | ||
| 703 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 704 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 705 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 706 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 707 | }, | ||
| 708 | .subresourceRange = | ||
| 709 | { | ||
| 710 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 711 | .baseMipLevel = 0, | ||
| 712 | .levelCount = 1, | ||
| 713 | .baseArrayLayer = 0, | ||
| 714 | .layerCount = 1, | ||
| 715 | }, | ||
| 716 | }); | ||
| 766 | } | 717 | } |
| 767 | } | 718 | } |
| 768 | 719 | ||
| @@ -789,7 +740,7 @@ void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView imag | |||
| 789 | const VkDescriptorImageInfo image_info{ | 740 | const VkDescriptorImageInfo image_info{ |
| 790 | .sampler = *sampler, | 741 | .sampler = *sampler, |
| 791 | .imageView = image_view, | 742 | .imageView = image_view, |
| 792 | .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, | 743 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, |
| 793 | }; | 744 | }; |
| 794 | 745 | ||
| 795 | const VkWriteDescriptorSet sampler_write{ | 746 | const VkWriteDescriptorSet sampler_write{ |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 8f2839214..69ed61770 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | 8 | ||
| 9 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 9 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 10 | #include "video_core/renderer_vulkan/wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | namespace Core { | 12 | namespace Core { |
| 13 | class System; | 13 | class System; |
| @@ -33,9 +33,8 @@ namespace Vulkan { | |||
| 33 | 33 | ||
| 34 | struct ScreenInfo; | 34 | struct ScreenInfo; |
| 35 | 35 | ||
| 36 | class Device; | ||
| 36 | class RasterizerVulkan; | 37 | class RasterizerVulkan; |
| 37 | class VKDevice; | ||
| 38 | class VKImage; | ||
| 39 | class VKScheduler; | 38 | class VKScheduler; |
| 40 | class VKSwapchain; | 39 | class VKSwapchain; |
| 41 | 40 | ||
| @@ -43,7 +42,7 @@ class VKBlitScreen final { | |||
| 43 | public: | 42 | public: |
| 44 | explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, | 43 | explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, |
| 45 | Core::Frontend::EmuWindow& render_window, | 44 | Core::Frontend::EmuWindow& render_window, |
| 46 | VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, | 45 | VideoCore::RasterizerInterface& rasterizer, const Device& device, |
| 47 | VKMemoryManager& memory_manager, VKSwapchain& swapchain, | 46 | VKMemoryManager& memory_manager, VKSwapchain& swapchain, |
| 48 | VKScheduler& scheduler, const VKScreenInfo& screen_info); | 47 | VKScheduler& scheduler, const VKScreenInfo& screen_info); |
| 49 | ~VKBlitScreen(); | 48 | ~VKBlitScreen(); |
| @@ -86,7 +85,7 @@ private: | |||
| 86 | Core::Memory::Memory& cpu_memory; | 85 | Core::Memory::Memory& cpu_memory; |
| 87 | Core::Frontend::EmuWindow& render_window; | 86 | Core::Frontend::EmuWindow& render_window; |
| 88 | VideoCore::RasterizerInterface& rasterizer; | 87 | VideoCore::RasterizerInterface& rasterizer; |
| 89 | const VKDevice& device; | 88 | const Device& device; |
| 90 | VKMemoryManager& memory_manager; | 89 | VKMemoryManager& memory_manager; |
| 91 | VKSwapchain& swapchain; | 90 | VKSwapchain& swapchain; |
| 92 | VKScheduler& scheduler; | 91 | VKScheduler& scheduler; |
| @@ -110,7 +109,8 @@ private: | |||
| 110 | std::vector<u64> resource_ticks; | 109 | std::vector<u64> resource_ticks; |
| 111 | 110 | ||
| 112 | std::vector<vk::Semaphore> semaphores; | 111 | std::vector<vk::Semaphore> semaphores; |
| 113 | std::vector<std::unique_ptr<VKImage>> raw_images; | 112 | std::vector<vk::Image> raw_images; |
| 113 | std::vector<vk::ImageView> raw_image_views; | ||
| 114 | std::vector<VKMemoryCommit> raw_buffer_commits; | 114 | std::vector<VKMemoryCommit> raw_buffer_commits; |
| 115 | u32 raw_width = 0; | 115 | u32 raw_width = 0; |
| 116 | u32 raw_height = 0; | 116 | u32 raw_height = 0; |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index d9d3da9ea..4d517c547 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -9,10 +9,10 @@ | |||
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "video_core/buffer_cache/buffer_cache.h" | 10 | #include "video_core/buffer_cache/buffer_cache.h" |
| 11 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 11 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 12 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 12 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 14 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" | 13 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" |
| 15 | #include "video_core/renderer_vulkan/wrapper.h" | 14 | #include "video_core/vulkan_common/vulkan_device.h" |
| 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 16 | 16 | ||
| 17 | namespace Vulkan { | 17 | namespace Vulkan { |
| 18 | 18 | ||
| @@ -31,20 +31,24 @@ constexpr VkAccessFlags UPLOAD_ACCESS_BARRIERS = | |||
| 31 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT | | 31 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT | |
| 32 | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT; | 32 | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT; |
| 33 | 33 | ||
| 34 | std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKScheduler& scheduler) { | 34 | constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS = |
| 35 | return std::make_unique<VKStreamBuffer>(device, scheduler, BUFFER_USAGE); | 35 | VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT; |
| 36 | |||
| 37 | std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const Device& device, VKScheduler& scheduler) { | ||
| 38 | return std::make_unique<VKStreamBuffer>(device, scheduler); | ||
| 36 | } | 39 | } |
| 37 | 40 | ||
| 38 | } // Anonymous namespace | 41 | } // Anonymous namespace |
| 39 | 42 | ||
| 40 | Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler_, | 43 | Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKScheduler& scheduler_, |
| 41 | VKStagingBufferPool& staging_pool_, VAddr cpu_addr, std::size_t size) | 44 | VKStagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) |
| 42 | : BufferBlock{cpu_addr, size}, scheduler{scheduler_}, staging_pool{staging_pool_} { | 45 | : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{ |
| 46 | staging_pool_} { | ||
| 43 | const VkBufferCreateInfo ci{ | 47 | const VkBufferCreateInfo ci{ |
| 44 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 48 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 45 | .pNext = nullptr, | 49 | .pNext = nullptr, |
| 46 | .flags = 0, | 50 | .flags = 0, |
| 47 | .size = static_cast<VkDeviceSize>(size), | 51 | .size = static_cast<VkDeviceSize>(size_), |
| 48 | .usage = BUFFER_USAGE | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, | 52 | .usage = BUFFER_USAGE | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| 49 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 53 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 50 | .queueFamilyIndexCount = 0, | 54 | .queueFamilyIndexCount = 0, |
| @@ -57,69 +61,86 @@ Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKSchedu | |||
| 57 | 61 | ||
| 58 | Buffer::~Buffer() = default; | 62 | Buffer::~Buffer() = default; |
| 59 | 63 | ||
| 60 | void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) { | 64 | void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { |
| 61 | const auto& staging = staging_pool.GetUnusedBuffer(size, true); | 65 | const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); |
| 62 | std::memcpy(staging.commit->Map(size), data, size); | 66 | std::memcpy(staging.commit->Map(data_size), data, data_size); |
| 63 | 67 | ||
| 64 | scheduler.RequestOutsideRenderPassOperationContext(); | 68 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 65 | 69 | ||
| 66 | const VkBuffer handle = Handle(); | 70 | const VkBuffer handle = Handle(); |
| 67 | scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) { | 71 | scheduler.Record([staging = *staging.handle, handle, offset, data_size, |
| 68 | cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, size}); | 72 | &device = device](vk::CommandBuffer cmdbuf) { |
| 69 | 73 | const VkBufferMemoryBarrier read_barrier{ | |
| 70 | const VkBufferMemoryBarrier barrier{ | ||
| 71 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 74 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| 72 | .pNext = nullptr, | 75 | .pNext = nullptr, |
| 73 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | 76 | .srcAccessMask = |
| 74 | .dstAccessMask = UPLOAD_ACCESS_BARRIERS, | 77 | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | |
| 78 | VK_ACCESS_HOST_WRITE_BIT | | ||
| 79 | (device.IsExtTransformFeedbackSupported() ? TRANSFORM_FEEDBACK_WRITE_ACCESS : 0), | ||
| 80 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 75 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 81 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 76 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 82 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 77 | .buffer = handle, | 83 | .buffer = handle, |
| 78 | .offset = offset, | 84 | .offset = offset, |
| 79 | .size = size, | 85 | .size = data_size, |
| 80 | }; | 86 | }; |
| 81 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, | 87 | const VkBufferMemoryBarrier write_barrier{ |
| 82 | barrier, {}); | ||
| 83 | }); | ||
| 84 | } | ||
| 85 | |||
| 86 | void Buffer::Download(std::size_t offset, std::size_t size, u8* data) { | ||
| 87 | const auto& staging = staging_pool.GetUnusedBuffer(size, true); | ||
| 88 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 89 | |||
| 90 | const VkBuffer handle = Handle(); | ||
| 91 | scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) { | ||
| 92 | const VkBufferMemoryBarrier barrier{ | ||
| 93 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 88 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| 94 | .pNext = nullptr, | 89 | .pNext = nullptr, |
| 95 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, | 90 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 96 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | 91 | .dstAccessMask = UPLOAD_ACCESS_BARRIERS, |
| 97 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 92 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 98 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 93 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 99 | .buffer = handle, | 94 | .buffer = handle, |
| 100 | .offset = offset, | 95 | .offset = offset, |
| 101 | .size = size, | 96 | .size = data_size, |
| 102 | }; | 97 | }; |
| 103 | 98 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | |
| 104 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | | 99 | 0, read_barrier); |
| 105 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | | 100 | cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, data_size}); |
| 106 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 101 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, |
| 107 | VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, barrier, {}); | 102 | write_barrier); |
| 108 | cmdbuf.CopyBuffer(handle, staging, VkBufferCopy{offset, 0, size}); | ||
| 109 | }); | 103 | }); |
| 104 | } | ||
| 105 | |||
| 106 | void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { | ||
| 107 | const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); | ||
| 108 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 109 | |||
| 110 | const VkBuffer handle = Handle(); | ||
| 111 | scheduler.Record( | ||
| 112 | [staging = *staging.handle, handle, offset, data_size](vk::CommandBuffer cmdbuf) { | ||
| 113 | const VkBufferMemoryBarrier barrier{ | ||
| 114 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | ||
| 115 | .pNext = nullptr, | ||
| 116 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, | ||
| 117 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 118 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 119 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 120 | .buffer = handle, | ||
| 121 | .offset = offset, | ||
| 122 | .size = data_size, | ||
| 123 | }; | ||
| 124 | |||
| 125 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | | ||
| 126 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | | ||
| 127 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 128 | VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, barrier, {}); | ||
| 129 | cmdbuf.CopyBuffer(handle, staging, VkBufferCopy{offset, 0, data_size}); | ||
| 130 | }); | ||
| 110 | scheduler.Finish(); | 131 | scheduler.Finish(); |
| 111 | 132 | ||
| 112 | std::memcpy(data, staging.commit->Map(size), size); | 133 | std::memcpy(data, staging.commit->Map(data_size), data_size); |
| 113 | } | 134 | } |
| 114 | 135 | ||
| 115 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, | 136 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, |
| 116 | std::size_t size) { | 137 | std::size_t copy_size) { |
| 117 | scheduler.RequestOutsideRenderPassOperationContext(); | 138 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 118 | 139 | ||
| 119 | const VkBuffer dst_buffer = Handle(); | 140 | const VkBuffer dst_buffer = Handle(); |
| 120 | scheduler.Record([src_buffer = src.Handle(), dst_buffer, src_offset, dst_offset, | 141 | scheduler.Record([src_buffer = src.Handle(), dst_buffer, src_offset, dst_offset, |
| 121 | size](vk::CommandBuffer cmdbuf) { | 142 | copy_size](vk::CommandBuffer cmdbuf) { |
| 122 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, VkBufferCopy{src_offset, dst_offset, size}); | 143 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, VkBufferCopy{src_offset, dst_offset, copy_size}); |
| 123 | 144 | ||
| 124 | std::array<VkBufferMemoryBarrier, 2> barriers; | 145 | std::array<VkBufferMemoryBarrier, 2> barriers; |
| 125 | barriers[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; | 146 | barriers[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; |
| @@ -130,7 +151,7 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst | |||
| 130 | barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | 151 | barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| 131 | barriers[0].buffer = src_buffer; | 152 | barriers[0].buffer = src_buffer; |
| 132 | barriers[0].offset = src_offset; | 153 | barriers[0].offset = src_offset; |
| 133 | barriers[0].size = size; | 154 | barriers[0].size = copy_size; |
| 134 | barriers[1].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; | 155 | barriers[1].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; |
| 135 | barriers[1].pNext = nullptr; | 156 | barriers[1].pNext = nullptr; |
| 136 | barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | 157 | barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
| @@ -139,19 +160,19 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst | |||
| 139 | barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | 160 | barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| 140 | barriers[1].buffer = dst_buffer; | 161 | barriers[1].buffer = dst_buffer; |
| 141 | barriers[1].offset = dst_offset; | 162 | barriers[1].offset = dst_offset; |
| 142 | barriers[1].size = size; | 163 | barriers[1].size = copy_size; |
| 143 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, | 164 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, |
| 144 | barriers, {}); | 165 | barriers, {}); |
| 145 | }); | 166 | }); |
| 146 | } | 167 | } |
| 147 | 168 | ||
| 148 | VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, | 169 | VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, |
| 149 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, | 170 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, |
| 150 | const VKDevice& device_, VKMemoryManager& memory_manager_, | 171 | const Device& device_, VKMemoryManager& memory_manager_, |
| 151 | VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_) | 172 | VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, |
| 152 | : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, gpu_memory, cpu_memory, | 173 | VKStagingBufferPool& staging_pool_) |
| 153 | CreateStreamBuffer(device_, | 174 | : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_, |
| 154 | scheduler_)}, | 175 | cpu_memory_, stream_buffer_}, |
| 155 | device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ | 176 | device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ |
| 156 | staging_pool_} {} | 177 | staging_pool_} {} |
| 157 | 178 | ||
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 7fb5ceedf..1c39aed34 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -11,26 +11,26 @@ | |||
| 11 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 11 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 12 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 12 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 13 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" | 13 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" |
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 15 | 15 | ||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | class VKDevice; | 18 | class Device; |
| 19 | class VKMemoryManager; | 19 | class VKMemoryManager; |
| 20 | class VKScheduler; | 20 | class VKScheduler; |
| 21 | 21 | ||
| 22 | class Buffer final : public VideoCommon::BufferBlock { | 22 | class Buffer final : public VideoCommon::BufferBlock { |
| 23 | public: | 23 | public: |
| 24 | explicit Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, | 24 | explicit Buffer(const Device& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, |
| 25 | VKStagingBufferPool& staging_pool, VAddr cpu_addr, std::size_t size); | 25 | VKStagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); |
| 26 | ~Buffer(); | 26 | ~Buffer(); |
| 27 | 27 | ||
| 28 | void Upload(std::size_t offset, std::size_t size, const u8* data); | 28 | void Upload(std::size_t offset, std::size_t data_size, const u8* data); |
| 29 | 29 | ||
| 30 | void Download(std::size_t offset, std::size_t size, u8* data); | 30 | void Download(std::size_t offset, std::size_t data_size, u8* data); |
| 31 | 31 | ||
| 32 | void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, | 32 | void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, |
| 33 | std::size_t size); | 33 | std::size_t copy_size); |
| 34 | 34 | ||
| 35 | VkBuffer Handle() const { | 35 | VkBuffer Handle() const { |
| 36 | return *buffer.handle; | 36 | return *buffer.handle; |
| @@ -41,6 +41,7 @@ public: | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | private: | 43 | private: |
| 44 | const Device& device; | ||
| 44 | VKScheduler& scheduler; | 45 | VKScheduler& scheduler; |
| 45 | VKStagingBufferPool& staging_pool; | 46 | VKStagingBufferPool& staging_pool; |
| 46 | 47 | ||
| @@ -51,8 +52,9 @@ class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VK | |||
| 51 | public: | 52 | public: |
| 52 | explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, | 53 | explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, |
| 53 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, | 54 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, |
| 54 | const VKDevice& device, VKMemoryManager& memory_manager, | 55 | const Device& device, VKMemoryManager& memory_manager, |
| 55 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool); | 56 | VKScheduler& scheduler, VKStreamBuffer& stream_buffer, |
| 57 | VKStagingBufferPool& staging_pool); | ||
| 56 | ~VKBufferCache(); | 58 | ~VKBufferCache(); |
| 57 | 59 | ||
| 58 | BufferInfo GetEmptyBuffer(std::size_t size) override; | 60 | BufferInfo GetEmptyBuffer(std::size_t size) override; |
| @@ -61,7 +63,7 @@ protected: | |||
| 61 | std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override; | 63 | std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override; |
| 62 | 64 | ||
| 63 | private: | 65 | private: |
| 64 | const VKDevice& device; | 66 | const Device& device; |
| 65 | VKMemoryManager& memory_manager; | 67 | VKMemoryManager& memory_manager; |
| 66 | VKScheduler& scheduler; | 68 | VKScheduler& scheduler; |
| 67 | VKStagingBufferPool& staging_pool; | 69 | VKStagingBufferPool& staging_pool; |
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp index f1abd4b1a..a99df9323 100644 --- a/src/video_core/renderer_vulkan/vk_command_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp | |||
| @@ -5,15 +5,20 @@ | |||
| 5 | #include <cstddef> | 5 | #include <cstddef> |
| 6 | 6 | ||
| 7 | #include "video_core/renderer_vulkan/vk_command_pool.h" | 7 | #include "video_core/renderer_vulkan/vk_command_pool.h" |
| 8 | #include "video_core/renderer_vulkan/vk_device.h" | 8 | #include "video_core/vulkan_common/vulkan_device.h" |
| 9 | #include "video_core/renderer_vulkan/wrapper.h" | 9 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 10 | 10 | ||
| 11 | namespace Vulkan { | 11 | namespace Vulkan { |
| 12 | 12 | ||
| 13 | constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; | 13 | constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; |
| 14 | 14 | ||
| 15 | CommandPool::CommandPool(MasterSemaphore& master_semaphore, const VKDevice& device) | 15 | struct CommandPool::Pool { |
| 16 | : ResourcePool(master_semaphore, COMMAND_BUFFER_POOL_SIZE), device{device} {} | 16 | vk::CommandPool handle; |
| 17 | vk::CommandBuffers cmdbufs; | ||
| 18 | }; | ||
| 19 | |||
| 20 | CommandPool::CommandPool(MasterSemaphore& master_semaphore_, const Device& device_) | ||
| 21 | : ResourcePool(master_semaphore_, COMMAND_BUFFER_POOL_SIZE), device{device_} {} | ||
| 17 | 22 | ||
| 18 | CommandPool::~CommandPool() = default; | 23 | CommandPool::~CommandPool() = default; |
| 19 | 24 | ||
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.h b/src/video_core/renderer_vulkan/vk_command_pool.h index 3aee239b9..61c26a22a 100644 --- a/src/video_core/renderer_vulkan/vk_command_pool.h +++ b/src/video_core/renderer_vulkan/vk_command_pool.h | |||
| @@ -2,33 +2,32 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | ||
| 6 | |||
| 5 | #include <cstddef> | 7 | #include <cstddef> |
| 6 | #include <vector> | 8 | #include <vector> |
| 7 | 9 | ||
| 8 | #include "video_core/renderer_vulkan/vk_resource_pool.h" | 10 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 9 | #include "video_core/renderer_vulkan/wrapper.h" | 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 10 | 12 | ||
| 11 | namespace Vulkan { | 13 | namespace Vulkan { |
| 12 | 14 | ||
| 15 | class Device; | ||
| 13 | class MasterSemaphore; | 16 | class MasterSemaphore; |
| 14 | class VKDevice; | ||
| 15 | 17 | ||
| 16 | class CommandPool final : public ResourcePool { | 18 | class CommandPool final : public ResourcePool { |
| 17 | public: | 19 | public: |
| 18 | explicit CommandPool(MasterSemaphore& master_semaphore, const VKDevice& device); | 20 | explicit CommandPool(MasterSemaphore& master_semaphore_, const Device& device_); |
| 19 | virtual ~CommandPool(); | 21 | ~CommandPool() override; |
| 20 | 22 | ||
| 21 | void Allocate(size_t begin, size_t end) override; | 23 | void Allocate(size_t begin, size_t end) override; |
| 22 | 24 | ||
| 23 | VkCommandBuffer Commit(); | 25 | VkCommandBuffer Commit(); |
| 24 | 26 | ||
| 25 | private: | 27 | private: |
| 26 | struct Pool { | 28 | struct Pool; |
| 27 | vk::CommandPool handle; | ||
| 28 | vk::CommandBuffers cmdbufs; | ||
| 29 | }; | ||
| 30 | 29 | ||
| 31 | const VKDevice& device; | 30 | const Device& device; |
| 32 | std::vector<Pool> pools; | 31 | std::vector<Pool> pools; |
| 33 | }; | 32 | }; |
| 34 | 33 | ||
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 9637c6059..02a6d54b7 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp | |||
| @@ -10,111 +10,21 @@ | |||
| 10 | #include "common/alignment.h" | 10 | #include "common/alignment.h" |
| 11 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "video_core/host_shaders/vulkan_quad_array_comp_spv.h" | ||
| 14 | #include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h" | ||
| 15 | #include "video_core/host_shaders/vulkan_uint8_comp_spv.h" | ||
| 13 | #include "video_core/renderer_vulkan/vk_compute_pass.h" | 16 | #include "video_core/renderer_vulkan/vk_compute_pass.h" |
| 14 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 17 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 15 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 16 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 18 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 17 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 19 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 18 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 20 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 19 | #include "video_core/renderer_vulkan/wrapper.h" | 21 | #include "video_core/vulkan_common/vulkan_device.h" |
| 22 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 20 | 23 | ||
| 21 | namespace Vulkan { | 24 | namespace Vulkan { |
| 22 | 25 | ||
| 23 | namespace { | 26 | namespace { |
| 24 | 27 | ||
| 25 | // Quad array SPIR-V module. Generated from the "shaders/" directory, read the instructions there. | ||
| 26 | constexpr u8 quad_array[] = { | ||
| 27 | 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x54, 0x00, 0x00, 0x00, | ||
| 28 | 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, | ||
| 29 | 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, | ||
| 30 | 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 31 | 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, | ||
| 32 | 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 33 | 0x11, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 34 | 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | ||
| 35 | 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 36 | 0x48, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 37 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 38 | 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 39 | 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 40 | 0x48, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 41 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x29, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 42 | 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 43 | 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 44 | 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 45 | 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 46 | 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 47 | 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 48 | 0x09, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 49 | 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 50 | 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 51 | 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 52 | 0x06, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 53 | 0x1e, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, | ||
| 54 | 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, | ||
| 55 | 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, | ||
| 56 | 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, | ||
| 57 | 0x1b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x29, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 58 | 0x20, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | ||
| 59 | 0x3b, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 60 | 0x2b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 61 | 0x20, 0x00, 0x04, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 62 | 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 63 | 0x1c, 0x00, 0x04, 0x00, 0x34, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 64 | 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 65 | 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 66 | 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 67 | 0x2c, 0x00, 0x09, 0x00, 0x34, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 68 | 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, | ||
| 69 | 0x37, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 70 | 0x34, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 71 | 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, | ||
| 72 | 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, | ||
| 73 | 0x00, 0x04, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, | ||
| 74 | 0x49, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, | ||
| 75 | 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 76 | 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x00, 0x00, | ||
| 77 | 0x3b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, | ||
| 78 | 0xf8, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, | ||
| 79 | 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x4d, 0x00, 0x00, 0x00, | ||
| 80 | 0xf8, 0x00, 0x02, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 81 | 0x0e, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, | ||
| 82 | 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, | ||
| 83 | 0x06, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 84 | 0x44, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | ||
| 85 | 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 86 | 0x17, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | ||
| 87 | 0x19, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | ||
| 88 | 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, | ||
| 89 | 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 90 | 0x1e, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, | ||
| 91 | 0x4b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, | ||
| 92 | 0x21, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, | ||
| 93 | 0x06, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | ||
| 94 | 0x48, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x00, 0x00, | ||
| 95 | 0x27, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, | ||
| 96 | 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, | ||
| 97 | 0x27, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, | ||
| 98 | 0x22, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, | ||
| 99 | 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 100 | 0x2f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 101 | 0x32, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, | ||
| 102 | 0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, | ||
| 103 | 0x3e, 0x00, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, | ||
| 104 | 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, | ||
| 105 | 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, | ||
| 106 | 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, | ||
| 107 | 0x3d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, | ||
| 108 | 0x12, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x44, 0x00, 0x00, 0x00, | ||
| 109 | 0x45, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, | ||
| 110 | 0x3e, 0x00, 0x03, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, | ||
| 111 | 0x06, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, | ||
| 112 | 0xf9, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 113 | 0xf9, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4e, 0x00, 0x00, 0x00, | ||
| 114 | 0xf9, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00, | ||
| 115 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, | ||
| 116 | }; | ||
| 117 | |||
| 118 | VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() { | 28 | VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() { |
| 119 | return { | 29 | return { |
| 120 | .binding = 0, | 30 | .binding = 0, |
| @@ -144,208 +54,6 @@ VkPushConstantRange BuildComputePushConstantRange(std::size_t size) { | |||
| 144 | }; | 54 | }; |
| 145 | } | 55 | } |
| 146 | 56 | ||
| 147 | // Uint8 SPIR-V module. Generated from the "shaders/" directory. | ||
| 148 | constexpr u8 uint8_pass[] = { | ||
| 149 | 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x2f, 0x00, 0x00, 0x00, | ||
| 150 | 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, | ||
| 151 | 0x51, 0x11, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x61, 0x11, 0x00, 0x00, 0x0a, 0x00, 0x07, 0x00, | ||
| 152 | 0x53, 0x50, 0x56, 0x5f, 0x4b, 0x48, 0x52, 0x5f, 0x31, 0x36, 0x62, 0x69, 0x74, 0x5f, 0x73, 0x74, | ||
| 153 | 0x6f, 0x72, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x53, 0x50, 0x56, 0x5f, | ||
| 154 | 0x4b, 0x48, 0x52, 0x5f, 0x38, 0x62, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, | ||
| 155 | 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, | ||
| 156 | 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, | ||
| 157 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 158 | 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 159 | 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, | ||
| 160 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 161 | 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 162 | 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 163 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 164 | 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, | ||
| 165 | 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 166 | 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 167 | 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, | ||
| 168 | 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 169 | 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 170 | 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, | ||
| 171 | 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 172 | 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 173 | 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, | ||
| 174 | 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 175 | 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, | ||
| 176 | 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, | ||
| 177 | 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, | ||
| 178 | 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, | ||
| 179 | 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, | ||
| 180 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, | ||
| 181 | 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, | ||
| 182 | 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, | ||
| 183 | 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00, | ||
| 184 | 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 185 | 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 186 | 0x13, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 187 | 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 188 | 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, | ||
| 189 | 0x1e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00, | ||
| 190 | 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 191 | 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 192 | 0x20, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 193 | 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 194 | 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 195 | 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 196 | 0x1e, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, | ||
| 197 | 0x00, 0x04, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, | ||
| 198 | 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, | ||
| 199 | 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, | ||
| 200 | 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 201 | 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 202 | 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 203 | 0x0e, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, | ||
| 204 | 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, | ||
| 205 | 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 206 | 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x44, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 207 | 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, | ||
| 208 | 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, | ||
| 209 | 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, | ||
| 210 | 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 211 | 0xf7, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, | ||
| 212 | 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, | ||
| 213 | 0x1c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | ||
| 214 | 0x08, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | ||
| 215 | 0x08, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | ||
| 216 | 0x15, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, | ||
| 217 | 0x11, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x71, 0x00, 0x04, 0x00, | ||
| 218 | 0x1e, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, | ||
| 219 | 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 220 | 0x24, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | ||
| 221 | 0xf9, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 222 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, | ||
| 223 | }; | ||
| 224 | |||
| 225 | // Quad indexed SPIR-V module. Generated from the "shaders/" directory. | ||
| 226 | constexpr u8 QUAD_INDEXED_SPV[] = { | ||
| 227 | 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x7c, 0x00, 0x00, 0x00, | ||
| 228 | 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, | ||
| 229 | 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, | ||
| 230 | 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 231 | 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, | ||
| 232 | 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 233 | 0x11, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 234 | 0x47, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | ||
| 235 | 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 236 | 0x48, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 237 | 0x48, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 238 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 239 | 0x47, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 240 | 0x47, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 241 | 0x48, 0x00, 0x05, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 242 | 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 243 | 0x23, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 244 | 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 245 | 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 246 | 0x18, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 247 | 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x57, 0x00, 0x00, 0x00, | ||
| 248 | 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 249 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 250 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 251 | 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, | ||
| 252 | 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 253 | 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 254 | 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 255 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 256 | 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 257 | 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 258 | 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 259 | 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 260 | 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 261 | 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 262 | 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 263 | 0x20, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | ||
| 264 | 0x3b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 265 | 0x14, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 266 | 0x21, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 267 | 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 268 | 0x09, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 269 | 0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 270 | 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, | ||
| 271 | 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 272 | 0x2b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 273 | 0x3b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 274 | 0x3f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, | ||
| 275 | 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 276 | 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 277 | 0x43, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x09, 0x00, 0x41, 0x00, 0x00, 0x00, | ||
| 278 | 0x44, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, | ||
| 279 | 0x42, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, | ||
| 280 | 0x46, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00, | ||
| 281 | 0x56, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x57, 0x00, 0x00, 0x00, | ||
| 282 | 0x56, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 283 | 0x57, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, | ||
| 284 | 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 285 | 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 286 | 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, | ||
| 287 | 0x00, 0x04, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, | ||
| 288 | 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, | ||
| 289 | 0x70, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, | ||
| 290 | 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 291 | 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00, | ||
| 292 | 0x47, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, | ||
| 293 | 0xf8, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x73, 0x00, 0x00, 0x00, | ||
| 294 | 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x75, 0x00, 0x00, 0x00, | ||
| 295 | 0xf8, 0x00, 0x02, 0x00, 0x75, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 296 | 0x0f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, | ||
| 297 | 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, | ||
| 298 | 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, | ||
| 299 | 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 300 | 0x44, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 301 | 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | ||
| 302 | 0x19, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | ||
| 303 | 0x14, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, | ||
| 304 | 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 305 | 0x1e, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, | ||
| 306 | 0x73, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, | ||
| 307 | 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | ||
| 308 | 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | ||
| 309 | 0xc4, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 310 | 0x28, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, | ||
| 311 | 0x2b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 312 | 0x31, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, | ||
| 313 | 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | ||
| 314 | 0xf9, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, | ||
| 315 | 0xf5, 0x00, 0x07, 0x00, 0x09, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 316 | 0x1e, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, | ||
| 317 | 0x1b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, | ||
| 318 | 0xf6, 0x00, 0x04, 0x00, 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 319 | 0xfa, 0x00, 0x04, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, | ||
| 320 | 0xf8, 0x00, 0x02, 0x00, 0x36, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 321 | 0x40, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, | ||
| 322 | 0x47, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 323 | 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, | ||
| 324 | 0x06, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, | ||
| 325 | 0x06, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, | ||
| 326 | 0xc3, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, | ||
| 327 | 0x2e, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, | ||
| 328 | 0x4a, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 329 | 0x54, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, | ||
| 330 | 0x5b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, | ||
| 331 | 0x4e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, | ||
| 332 | 0x5c, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, | ||
| 333 | 0x5d, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, | ||
| 334 | 0x09, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, | ||
| 335 | 0x09, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, | ||
| 336 | 0x41, 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | ||
| 337 | 0x42, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, | ||
| 338 | 0x6a, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, | ||
| 339 | 0x62, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5b, 0x00, 0x00, 0x00, | ||
| 340 | 0x6d, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, | ||
| 341 | 0x3e, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, | ||
| 342 | 0x09, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | ||
| 343 | 0xf9, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x37, 0x00, 0x00, 0x00, | ||
| 344 | 0xf9, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, 0x00, | ||
| 345 | 0xf9, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, | ||
| 346 | 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, | ||
| 347 | }; | ||
| 348 | |||
| 349 | std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() { | 57 | std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() { |
| 350 | return {{ | 58 | return {{ |
| 351 | { | 59 | { |
| @@ -378,11 +86,11 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() { | |||
| 378 | 86 | ||
| 379 | } // Anonymous namespace | 87 | } // Anonymous namespace |
| 380 | 88 | ||
| 381 | VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool, | 89 | VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool, |
| 382 | vk::Span<VkDescriptorSetLayoutBinding> bindings, | 90 | vk::Span<VkDescriptorSetLayoutBinding> bindings, |
| 383 | vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, | 91 | vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, |
| 384 | vk::Span<VkPushConstantRange> push_constants, std::size_t code_size, | 92 | vk::Span<VkPushConstantRange> push_constants, |
| 385 | const u8* code) { | 93 | std::span<const u32> code) { |
| 386 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout({ | 94 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout({ |
| 387 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | 95 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, |
| 388 | .pNext = nullptr, | 96 | .pNext = nullptr, |
| @@ -390,7 +98,6 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto | |||
| 390 | .bindingCount = bindings.size(), | 98 | .bindingCount = bindings.size(), |
| 391 | .pBindings = bindings.data(), | 99 | .pBindings = bindings.data(), |
| 392 | }); | 100 | }); |
| 393 | |||
| 394 | layout = device.GetLogical().CreatePipelineLayout({ | 101 | layout = device.GetLogical().CreatePipelineLayout({ |
| 395 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | 102 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
| 396 | .pNext = nullptr, | 103 | .pNext = nullptr, |
| @@ -400,7 +107,6 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto | |||
| 400 | .pushConstantRangeCount = push_constants.size(), | 107 | .pushConstantRangeCount = push_constants.size(), |
| 401 | .pPushConstantRanges = push_constants.data(), | 108 | .pPushConstantRanges = push_constants.data(), |
| 402 | }); | 109 | }); |
| 403 | |||
| 404 | if (!templates.empty()) { | 110 | if (!templates.empty()) { |
| 405 | descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR({ | 111 | descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR({ |
| 406 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, | 112 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, |
| @@ -417,18 +123,13 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto | |||
| 417 | 123 | ||
| 418 | descriptor_allocator.emplace(descriptor_pool, *descriptor_set_layout); | 124 | descriptor_allocator.emplace(descriptor_pool, *descriptor_set_layout); |
| 419 | } | 125 | } |
| 420 | |||
| 421 | auto code_copy = std::make_unique<u32[]>(code_size / sizeof(u32) + 1); | ||
| 422 | std::memcpy(code_copy.get(), code, code_size); | ||
| 423 | |||
| 424 | module = device.GetLogical().CreateShaderModule({ | 126 | module = device.GetLogical().CreateShaderModule({ |
| 425 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | 127 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, |
| 426 | .pNext = nullptr, | 128 | .pNext = nullptr, |
| 427 | .flags = 0, | 129 | .flags = 0, |
| 428 | .codeSize = code_size, | 130 | .codeSize = static_cast<u32>(code.size_bytes()), |
| 429 | .pCode = code_copy.get(), | 131 | .pCode = code.data(), |
| 430 | }); | 132 | }); |
| 431 | |||
| 432 | pipeline = device.GetLogical().CreateComputePipeline({ | 133 | pipeline = device.GetLogical().CreateComputePipeline({ |
| 433 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, | 134 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, |
| 434 | .pNext = nullptr, | 135 | .pNext = nullptr, |
| @@ -461,15 +162,15 @@ VkDescriptorSet VKComputePass::CommitDescriptorSet( | |||
| 461 | return set; | 162 | return set; |
| 462 | } | 163 | } |
| 463 | 164 | ||
| 464 | QuadArrayPass::QuadArrayPass(const VKDevice& device, VKScheduler& scheduler, | 165 | QuadArrayPass::QuadArrayPass(const Device& device_, VKScheduler& scheduler_, |
| 465 | VKDescriptorPool& descriptor_pool, | 166 | VKDescriptorPool& descriptor_pool_, |
| 466 | VKStagingBufferPool& staging_buffer_pool, | 167 | VKStagingBufferPool& staging_buffer_pool_, |
| 467 | VKUpdateDescriptorQueue& update_descriptor_queue) | 168 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 468 | : VKComputePass(device, descriptor_pool, BuildQuadArrayPassDescriptorSetLayoutBinding(), | 169 | : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(), |
| 469 | BuildQuadArrayPassDescriptorUpdateTemplateEntry(), | 170 | BuildQuadArrayPassDescriptorUpdateTemplateEntry(), |
| 470 | BuildComputePushConstantRange(sizeof(u32)), std::size(quad_array), quad_array), | 171 | BuildComputePushConstantRange(sizeof(u32)), VULKAN_QUAD_ARRAY_COMP_SPV), |
| 471 | scheduler{scheduler}, staging_buffer_pool{staging_buffer_pool}, | 172 | scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, |
| 472 | update_descriptor_queue{update_descriptor_queue} {} | 173 | update_descriptor_queue{update_descriptor_queue_} {} |
| 473 | 174 | ||
| 474 | QuadArrayPass::~QuadArrayPass() = default; | 175 | QuadArrayPass::~QuadArrayPass() = default; |
| 475 | 176 | ||
| @@ -510,14 +211,13 @@ std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 | |||
| 510 | return {*buffer.handle, 0}; | 211 | return {*buffer.handle, 0}; |
| 511 | } | 212 | } |
| 512 | 213 | ||
| 513 | Uint8Pass::Uint8Pass(const VKDevice& device, VKScheduler& scheduler, | 214 | Uint8Pass::Uint8Pass(const Device& device, VKScheduler& scheduler_, |
| 514 | VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool, | 215 | VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool_, |
| 515 | VKUpdateDescriptorQueue& update_descriptor_queue) | 216 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 516 | : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), | 217 | : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), |
| 517 | BuildInputOutputDescriptorUpdateTemplate(), {}, std::size(uint8_pass), | 218 | BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV), |
| 518 | uint8_pass), | 219 | scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, |
| 519 | scheduler{scheduler}, staging_buffer_pool{staging_buffer_pool}, | 220 | update_descriptor_queue{update_descriptor_queue_} {} |
| 520 | update_descriptor_queue{update_descriptor_queue} {} | ||
| 521 | 221 | ||
| 522 | Uint8Pass::~Uint8Pass() = default; | 222 | Uint8Pass::~Uint8Pass() = default; |
| 523 | 223 | ||
| @@ -555,16 +255,15 @@ std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buff | |||
| 555 | return {*buffer.handle, 0}; | 255 | return {*buffer.handle, 0}; |
| 556 | } | 256 | } |
| 557 | 257 | ||
| 558 | QuadIndexedPass::QuadIndexedPass(const VKDevice& device, VKScheduler& scheduler, | 258 | QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, |
| 559 | VKDescriptorPool& descriptor_pool, | 259 | VKDescriptorPool& descriptor_pool_, |
| 560 | VKStagingBufferPool& staging_buffer_pool, | 260 | VKStagingBufferPool& staging_buffer_pool_, |
| 561 | VKUpdateDescriptorQueue& update_descriptor_queue) | 261 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 562 | : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), | 262 | : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), |
| 563 | BuildInputOutputDescriptorUpdateTemplate(), | 263 | BuildInputOutputDescriptorUpdateTemplate(), |
| 564 | BuildComputePushConstantRange(sizeof(u32) * 2), std::size(QUAD_INDEXED_SPV), | 264 | BuildComputePushConstantRange(sizeof(u32) * 2), VULKAN_QUAD_INDEXED_COMP_SPV), |
| 565 | QUAD_INDEXED_SPV), | 265 | scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, |
| 566 | scheduler{scheduler}, staging_buffer_pool{staging_buffer_pool}, | 266 | update_descriptor_queue{update_descriptor_queue_} {} |
| 567 | update_descriptor_queue{update_descriptor_queue} {} | ||
| 568 | 267 | ||
| 569 | QuadIndexedPass::~QuadIndexedPass() = default; | 268 | QuadIndexedPass::~QuadIndexedPass() = default; |
| 570 | 269 | ||
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index acc94f27e..7ddb09afb 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h | |||
| @@ -5,27 +5,27 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <optional> | 7 | #include <optional> |
| 8 | #include <span> | ||
| 8 | #include <utility> | 9 | #include <utility> |
| 9 | 10 | ||
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | #include "video_core/engines/maxwell_3d.h" | 12 | #include "video_core/engines/maxwell_3d.h" |
| 12 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 13 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 13 | #include "video_core/renderer_vulkan/wrapper.h" | 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 14 | 15 | ||
| 15 | namespace Vulkan { | 16 | namespace Vulkan { |
| 16 | 17 | ||
| 17 | class VKDevice; | 18 | class Device; |
| 18 | class VKScheduler; | 19 | class VKScheduler; |
| 19 | class VKStagingBufferPool; | 20 | class VKStagingBufferPool; |
| 20 | class VKUpdateDescriptorQueue; | 21 | class VKUpdateDescriptorQueue; |
| 21 | 22 | ||
| 22 | class VKComputePass { | 23 | class VKComputePass { |
| 23 | public: | 24 | public: |
| 24 | explicit VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool, | 25 | explicit VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool, |
| 25 | vk::Span<VkDescriptorSetLayoutBinding> bindings, | 26 | vk::Span<VkDescriptorSetLayoutBinding> bindings, |
| 26 | vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, | 27 | vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, |
| 27 | vk::Span<VkPushConstantRange> push_constants, std::size_t code_size, | 28 | vk::Span<VkPushConstantRange> push_constants, std::span<const u32> code); |
| 28 | const u8* code); | ||
| 29 | ~VKComputePass(); | 29 | ~VKComputePass(); |
| 30 | 30 | ||
| 31 | protected: | 31 | protected: |
| @@ -43,10 +43,10 @@ private: | |||
| 43 | 43 | ||
| 44 | class QuadArrayPass final : public VKComputePass { | 44 | class QuadArrayPass final : public VKComputePass { |
| 45 | public: | 45 | public: |
| 46 | explicit QuadArrayPass(const VKDevice& device, VKScheduler& scheduler, | 46 | explicit QuadArrayPass(const Device& device_, VKScheduler& scheduler_, |
| 47 | VKDescriptorPool& descriptor_pool, | 47 | VKDescriptorPool& descriptor_pool_, |
| 48 | VKStagingBufferPool& staging_buffer_pool, | 48 | VKStagingBufferPool& staging_buffer_pool_, |
| 49 | VKUpdateDescriptorQueue& update_descriptor_queue); | 49 | VKUpdateDescriptorQueue& update_descriptor_queue_); |
| 50 | ~QuadArrayPass(); | 50 | ~QuadArrayPass(); |
| 51 | 51 | ||
| 52 | std::pair<VkBuffer, VkDeviceSize> Assemble(u32 num_vertices, u32 first); | 52 | std::pair<VkBuffer, VkDeviceSize> Assemble(u32 num_vertices, u32 first); |
| @@ -59,9 +59,10 @@ private: | |||
| 59 | 59 | ||
| 60 | class Uint8Pass final : public VKComputePass { | 60 | class Uint8Pass final : public VKComputePass { |
| 61 | public: | 61 | public: |
| 62 | explicit Uint8Pass(const VKDevice& device, VKScheduler& scheduler, | 62 | explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_, |
| 63 | VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool, | 63 | VKDescriptorPool& descriptor_pool_, |
| 64 | VKUpdateDescriptorQueue& update_descriptor_queue); | 64 | VKStagingBufferPool& staging_buffer_pool_, |
| 65 | VKUpdateDescriptorQueue& update_descriptor_queue_); | ||
| 65 | ~Uint8Pass(); | 66 | ~Uint8Pass(); |
| 66 | 67 | ||
| 67 | std::pair<VkBuffer, u64> Assemble(u32 num_vertices, VkBuffer src_buffer, u64 src_offset); | 68 | std::pair<VkBuffer, u64> Assemble(u32 num_vertices, VkBuffer src_buffer, u64 src_offset); |
| @@ -74,10 +75,10 @@ private: | |||
| 74 | 75 | ||
| 75 | class QuadIndexedPass final : public VKComputePass { | 76 | class QuadIndexedPass final : public VKComputePass { |
| 76 | public: | 77 | public: |
| 77 | explicit QuadIndexedPass(const VKDevice& device, VKScheduler& scheduler, | 78 | explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, |
| 78 | VKDescriptorPool& descriptor_pool, | 79 | VKDescriptorPool& descriptor_pool_, |
| 79 | VKStagingBufferPool& staging_buffer_pool, | 80 | VKStagingBufferPool& staging_buffer_pool_, |
| 80 | VKUpdateDescriptorQueue& update_descriptor_queue); | 81 | VKUpdateDescriptorQueue& update_descriptor_queue_); |
| 81 | ~QuadIndexedPass(); | 82 | ~QuadIndexedPass(); |
| 82 | 83 | ||
| 83 | std::pair<VkBuffer, u64> Assemble(Tegra::Engines::Maxwell3D::Regs::IndexFormat index_format, | 84 | std::pair<VkBuffer, u64> Assemble(Tegra::Engines::Maxwell3D::Regs::IndexFormat index_format, |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 9be72dc9b..3a48219b7 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | |||
| @@ -6,25 +6,25 @@ | |||
| 6 | 6 | ||
| 7 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" | 7 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" |
| 8 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 8 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 9 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 11 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 10 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 12 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | 11 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" |
| 13 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 12 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_device.h" |
| 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 15 | 15 | ||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | VKComputePipeline::VKComputePipeline(const VKDevice& device, VKScheduler& scheduler, | 18 | VKComputePipeline::VKComputePipeline(const Device& device_, VKScheduler& scheduler_, |
| 19 | VKDescriptorPool& descriptor_pool, | 19 | VKDescriptorPool& descriptor_pool_, |
| 20 | VKUpdateDescriptorQueue& update_descriptor_queue, | 20 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 21 | const SPIRVShader& shader) | 21 | const SPIRVShader& shader_) |
| 22 | : device{device}, scheduler{scheduler}, entries{shader.entries}, | 22 | : device{device_}, scheduler{scheduler_}, entries{shader_.entries}, |
| 23 | descriptor_set_layout{CreateDescriptorSetLayout()}, | 23 | descriptor_set_layout{CreateDescriptorSetLayout()}, |
| 24 | descriptor_allocator{descriptor_pool, *descriptor_set_layout}, | 24 | descriptor_allocator{descriptor_pool_, *descriptor_set_layout}, |
| 25 | update_descriptor_queue{update_descriptor_queue}, layout{CreatePipelineLayout()}, | 25 | update_descriptor_queue{update_descriptor_queue_}, layout{CreatePipelineLayout()}, |
| 26 | descriptor_template{CreateDescriptorUpdateTemplate()}, | 26 | descriptor_template{CreateDescriptorUpdateTemplate()}, |
| 27 | shader_module{CreateShaderModule(shader.code)}, pipeline{CreatePipeline()} {} | 27 | shader_module{CreateShaderModule(shader_.code)}, pipeline{CreatePipeline()} {} |
| 28 | 28 | ||
| 29 | VKComputePipeline::~VKComputePipeline() = default; | 29 | VKComputePipeline::~VKComputePipeline() = default; |
| 30 | 30 | ||
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 6e2f22a4a..7e16575ac 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h | |||
| @@ -7,20 +7,20 @@ | |||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 8 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 9 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | 9 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" |
| 10 | #include "video_core/renderer_vulkan/wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | namespace Vulkan { | 12 | namespace Vulkan { |
| 13 | 13 | ||
| 14 | class VKDevice; | 14 | class Device; |
| 15 | class VKScheduler; | 15 | class VKScheduler; |
| 16 | class VKUpdateDescriptorQueue; | 16 | class VKUpdateDescriptorQueue; |
| 17 | 17 | ||
| 18 | class VKComputePipeline final { | 18 | class VKComputePipeline final { |
| 19 | public: | 19 | public: |
| 20 | explicit VKComputePipeline(const VKDevice& device, VKScheduler& scheduler, | 20 | explicit VKComputePipeline(const Device& device_, VKScheduler& scheduler_, |
| 21 | VKDescriptorPool& descriptor_pool, | 21 | VKDescriptorPool& descriptor_pool_, |
| 22 | VKUpdateDescriptorQueue& update_descriptor_queue, | 22 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 23 | const SPIRVShader& shader); | 23 | const SPIRVShader& shader_); |
| 24 | ~VKComputePipeline(); | 24 | ~VKComputePipeline(); |
| 25 | 25 | ||
| 26 | VkDescriptorSet CommitDescriptorSet(); | 26 | VkDescriptorSet CommitDescriptorSet(); |
| @@ -48,7 +48,7 @@ private: | |||
| 48 | 48 | ||
| 49 | vk::Pipeline CreatePipeline() const; | 49 | vk::Pipeline CreatePipeline() const; |
| 50 | 50 | ||
| 51 | const VKDevice& device; | 51 | const Device& device; |
| 52 | VKScheduler& scheduler; | 52 | VKScheduler& scheduler; |
| 53 | ShaderEntries entries; | 53 | ShaderEntries entries; |
| 54 | 54 | ||
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index f38e089d5..ef9fb5910 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp | |||
| @@ -6,10 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 8 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_resource_pool.h" | 9 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 11 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 10 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 12 | #include "video_core/renderer_vulkan/wrapper.h" | 11 | #include "video_core/vulkan_common/vulkan_device.h" |
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | 13 | ||
| 14 | namespace Vulkan { | 14 | namespace Vulkan { |
| 15 | 15 | ||
| @@ -32,7 +32,7 @@ void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) { | |||
| 32 | descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin)); | 32 | descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin)); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | VKDescriptorPool::VKDescriptorPool(const VKDevice& device_, VKScheduler& scheduler) | 35 | VKDescriptorPool::VKDescriptorPool(const Device& device_, VKScheduler& scheduler) |
| 36 | : device{device_}, master_semaphore{scheduler.GetMasterSemaphore()}, active_pool{ | 36 | : device{device_}, master_semaphore{scheduler.GetMasterSemaphore()}, active_pool{ |
| 37 | AllocateNewPool()} {} | 37 | AllocateNewPool()} {} |
| 38 | 38 | ||
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h index 544f32a20..f892be7be 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h | |||
| @@ -7,11 +7,11 @@ | |||
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | 8 | ||
| 9 | #include "video_core/renderer_vulkan/vk_resource_pool.h" | 9 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 10 | #include "video_core/renderer_vulkan/wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | namespace Vulkan { | 12 | namespace Vulkan { |
| 13 | 13 | ||
| 14 | class VKDevice; | 14 | class Device; |
| 15 | class VKDescriptorPool; | 15 | class VKDescriptorPool; |
| 16 | class VKScheduler; | 16 | class VKScheduler; |
| 17 | 17 | ||
| @@ -39,7 +39,7 @@ class VKDescriptorPool final { | |||
| 39 | friend DescriptorAllocator; | 39 | friend DescriptorAllocator; |
| 40 | 40 | ||
| 41 | public: | 41 | public: |
| 42 | explicit VKDescriptorPool(const VKDevice& device, VKScheduler& scheduler); | 42 | explicit VKDescriptorPool(const Device& device, VKScheduler& scheduler); |
| 43 | ~VKDescriptorPool(); | 43 | ~VKDescriptorPool(); |
| 44 | 44 | ||
| 45 | VKDescriptorPool(const VKDescriptorPool&) = delete; | 45 | VKDescriptorPool(const VKDescriptorPool&) = delete; |
| @@ -50,7 +50,7 @@ private: | |||
| 50 | 50 | ||
| 51 | vk::DescriptorSets AllocateDescriptors(VkDescriptorSetLayout layout, std::size_t count); | 51 | vk::DescriptorSets AllocateDescriptors(VkDescriptorSetLayout layout, std::size_t count); |
| 52 | 52 | ||
| 53 | const VKDevice& device; | 53 | const Device& device; |
| 54 | MasterSemaphore& master_semaphore; | 54 | MasterSemaphore& master_semaphore; |
| 55 | 55 | ||
| 56 | std::vector<vk::DescriptorPool> pools; | 56 | std::vector<vk::DescriptorPool> pools; |
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp deleted file mode 100644 index 05e31f1de..000000000 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ /dev/null | |||
| @@ -1,801 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <bitset> | ||
| 6 | #include <chrono> | ||
| 7 | #include <optional> | ||
| 8 | #include <string_view> | ||
| 9 | #include <thread> | ||
| 10 | #include <unordered_set> | ||
| 11 | #include <utility> | ||
| 12 | #include <vector> | ||
| 13 | |||
| 14 | #include "common/assert.h" | ||
| 15 | #include "core/settings.h" | ||
| 16 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 17 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 18 | |||
| 19 | namespace Vulkan { | ||
| 20 | |||
| 21 | namespace { | ||
| 22 | |||
| 23 | namespace Alternatives { | ||
| 24 | |||
| 25 | constexpr std::array Depth24UnormS8_UINT{ | ||
| 26 | VK_FORMAT_D32_SFLOAT_S8_UINT, | ||
| 27 | VK_FORMAT_D16_UNORM_S8_UINT, | ||
| 28 | VkFormat{}, | ||
| 29 | }; | ||
| 30 | |||
| 31 | constexpr std::array Depth16UnormS8_UINT{ | ||
| 32 | VK_FORMAT_D24_UNORM_S8_UINT, | ||
| 33 | VK_FORMAT_D32_SFLOAT_S8_UINT, | ||
| 34 | VkFormat{}, | ||
| 35 | }; | ||
| 36 | |||
| 37 | } // namespace Alternatives | ||
| 38 | |||
| 39 | constexpr std::array REQUIRED_EXTENSIONS{ | ||
| 40 | VK_KHR_SWAPCHAIN_EXTENSION_NAME, | ||
| 41 | VK_KHR_16BIT_STORAGE_EXTENSION_NAME, | ||
| 42 | VK_KHR_8BIT_STORAGE_EXTENSION_NAME, | ||
| 43 | VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, | ||
| 44 | VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, | ||
| 45 | VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, | ||
| 46 | VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, | ||
| 47 | VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, | ||
| 48 | VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, | ||
| 49 | VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, | ||
| 50 | }; | ||
| 51 | |||
| 52 | template <typename T> | ||
| 53 | void SetNext(void**& next, T& data) { | ||
| 54 | *next = &data; | ||
| 55 | next = &data.pNext; | ||
| 56 | } | ||
| 57 | |||
| 58 | constexpr const VkFormat* GetFormatAlternatives(VkFormat format) { | ||
| 59 | switch (format) { | ||
| 60 | case VK_FORMAT_D24_UNORM_S8_UINT: | ||
| 61 | return Alternatives::Depth24UnormS8_UINT.data(); | ||
| 62 | case VK_FORMAT_D16_UNORM_S8_UINT: | ||
| 63 | return Alternatives::Depth16UnormS8_UINT.data(); | ||
| 64 | default: | ||
| 65 | return nullptr; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | VkFormatFeatureFlags GetFormatFeatures(VkFormatProperties properties, FormatType format_type) { | ||
| 70 | switch (format_type) { | ||
| 71 | case FormatType::Linear: | ||
| 72 | return properties.linearTilingFeatures; | ||
| 73 | case FormatType::Optimal: | ||
| 74 | return properties.optimalTilingFeatures; | ||
| 75 | case FormatType::Buffer: | ||
| 76 | return properties.bufferFeatures; | ||
| 77 | default: | ||
| 78 | return {}; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( | ||
| 83 | vk::PhysicalDevice physical, const vk::InstanceDispatch& dld) { | ||
| 84 | static constexpr std::array formats{ | ||
| 85 | VK_FORMAT_A8B8G8R8_UNORM_PACK32, | ||
| 86 | VK_FORMAT_A8B8G8R8_UINT_PACK32, | ||
| 87 | VK_FORMAT_A8B8G8R8_SNORM_PACK32, | ||
| 88 | VK_FORMAT_A8B8G8R8_SINT_PACK32, | ||
| 89 | VK_FORMAT_A8B8G8R8_SRGB_PACK32, | ||
| 90 | VK_FORMAT_B5G6R5_UNORM_PACK16, | ||
| 91 | VK_FORMAT_A2B10G10R10_UNORM_PACK32, | ||
| 92 | VK_FORMAT_A2B10G10R10_UINT_PACK32, | ||
| 93 | VK_FORMAT_A1R5G5B5_UNORM_PACK16, | ||
| 94 | VK_FORMAT_R32G32B32A32_SFLOAT, | ||
| 95 | VK_FORMAT_R32G32B32A32_SINT, | ||
| 96 | VK_FORMAT_R32G32B32A32_UINT, | ||
| 97 | VK_FORMAT_R32G32_SFLOAT, | ||
| 98 | VK_FORMAT_R32G32_SINT, | ||
| 99 | VK_FORMAT_R32G32_UINT, | ||
| 100 | VK_FORMAT_R16G16B16A16_SINT, | ||
| 101 | VK_FORMAT_R16G16B16A16_UINT, | ||
| 102 | VK_FORMAT_R16G16B16A16_SNORM, | ||
| 103 | VK_FORMAT_R16G16B16A16_UNORM, | ||
| 104 | VK_FORMAT_R16G16_UNORM, | ||
| 105 | VK_FORMAT_R16G16_SNORM, | ||
| 106 | VK_FORMAT_R16G16_SFLOAT, | ||
| 107 | VK_FORMAT_R16_UNORM, | ||
| 108 | VK_FORMAT_R16_UINT, | ||
| 109 | VK_FORMAT_R8G8B8A8_SRGB, | ||
| 110 | VK_FORMAT_R8G8_UNORM, | ||
| 111 | VK_FORMAT_R8G8_SNORM, | ||
| 112 | VK_FORMAT_R8G8_SINT, | ||
| 113 | VK_FORMAT_R8G8_UINT, | ||
| 114 | VK_FORMAT_R8_UNORM, | ||
| 115 | VK_FORMAT_R8_SNORM, | ||
| 116 | VK_FORMAT_R8_SINT, | ||
| 117 | VK_FORMAT_R8_UINT, | ||
| 118 | VK_FORMAT_B10G11R11_UFLOAT_PACK32, | ||
| 119 | VK_FORMAT_R32_SFLOAT, | ||
| 120 | VK_FORMAT_R32_UINT, | ||
| 121 | VK_FORMAT_R32_SINT, | ||
| 122 | VK_FORMAT_R16_SFLOAT, | ||
| 123 | VK_FORMAT_R16G16B16A16_SFLOAT, | ||
| 124 | VK_FORMAT_B8G8R8A8_UNORM, | ||
| 125 | VK_FORMAT_B8G8R8A8_SRGB, | ||
| 126 | VK_FORMAT_R4G4B4A4_UNORM_PACK16, | ||
| 127 | VK_FORMAT_D32_SFLOAT, | ||
| 128 | VK_FORMAT_D16_UNORM, | ||
| 129 | VK_FORMAT_D16_UNORM_S8_UINT, | ||
| 130 | VK_FORMAT_D24_UNORM_S8_UINT, | ||
| 131 | VK_FORMAT_D32_SFLOAT_S8_UINT, | ||
| 132 | VK_FORMAT_BC1_RGBA_UNORM_BLOCK, | ||
| 133 | VK_FORMAT_BC2_UNORM_BLOCK, | ||
| 134 | VK_FORMAT_BC3_UNORM_BLOCK, | ||
| 135 | VK_FORMAT_BC4_UNORM_BLOCK, | ||
| 136 | VK_FORMAT_BC4_SNORM_BLOCK, | ||
| 137 | VK_FORMAT_BC5_UNORM_BLOCK, | ||
| 138 | VK_FORMAT_BC5_SNORM_BLOCK, | ||
| 139 | VK_FORMAT_BC7_UNORM_BLOCK, | ||
| 140 | VK_FORMAT_BC6H_UFLOAT_BLOCK, | ||
| 141 | VK_FORMAT_BC6H_SFLOAT_BLOCK, | ||
| 142 | VK_FORMAT_BC1_RGBA_SRGB_BLOCK, | ||
| 143 | VK_FORMAT_BC2_SRGB_BLOCK, | ||
| 144 | VK_FORMAT_BC3_SRGB_BLOCK, | ||
| 145 | VK_FORMAT_BC7_SRGB_BLOCK, | ||
| 146 | VK_FORMAT_ASTC_4x4_SRGB_BLOCK, | ||
| 147 | VK_FORMAT_ASTC_8x8_SRGB_BLOCK, | ||
| 148 | VK_FORMAT_ASTC_8x5_SRGB_BLOCK, | ||
| 149 | VK_FORMAT_ASTC_5x4_SRGB_BLOCK, | ||
| 150 | VK_FORMAT_ASTC_5x5_UNORM_BLOCK, | ||
| 151 | VK_FORMAT_ASTC_5x5_SRGB_BLOCK, | ||
| 152 | VK_FORMAT_ASTC_10x8_UNORM_BLOCK, | ||
| 153 | VK_FORMAT_ASTC_10x8_SRGB_BLOCK, | ||
| 154 | VK_FORMAT_ASTC_6x6_UNORM_BLOCK, | ||
| 155 | VK_FORMAT_ASTC_6x6_SRGB_BLOCK, | ||
| 156 | VK_FORMAT_ASTC_10x10_UNORM_BLOCK, | ||
| 157 | VK_FORMAT_ASTC_10x10_SRGB_BLOCK, | ||
| 158 | VK_FORMAT_ASTC_12x12_UNORM_BLOCK, | ||
| 159 | VK_FORMAT_ASTC_12x12_SRGB_BLOCK, | ||
| 160 | VK_FORMAT_ASTC_8x6_UNORM_BLOCK, | ||
| 161 | VK_FORMAT_ASTC_8x6_SRGB_BLOCK, | ||
| 162 | VK_FORMAT_ASTC_6x5_UNORM_BLOCK, | ||
| 163 | VK_FORMAT_ASTC_6x5_SRGB_BLOCK, | ||
| 164 | VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, | ||
| 165 | }; | ||
| 166 | std::unordered_map<VkFormat, VkFormatProperties> format_properties; | ||
| 167 | for (const auto format : formats) { | ||
| 168 | format_properties.emplace(format, physical.GetFormatProperties(format)); | ||
| 169 | } | ||
| 170 | return format_properties; | ||
| 171 | } | ||
| 172 | |||
| 173 | } // Anonymous namespace | ||
| 174 | |||
| 175 | VKDevice::VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, | ||
| 176 | const vk::InstanceDispatch& dld) | ||
| 177 | : dld{dld}, physical{physical}, properties{physical.GetProperties()}, | ||
| 178 | format_properties{GetFormatProperties(physical, dld)} { | ||
| 179 | SetupFamilies(surface); | ||
| 180 | SetupFeatures(); | ||
| 181 | } | ||
| 182 | |||
| 183 | VKDevice::~VKDevice() = default; | ||
| 184 | |||
| 185 | bool VKDevice::Create() { | ||
| 186 | const auto queue_cis = GetDeviceQueueCreateInfos(); | ||
| 187 | const std::vector extensions = LoadExtensions(); | ||
| 188 | |||
| 189 | VkPhysicalDeviceFeatures2 features2{ | ||
| 190 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, | ||
| 191 | .pNext = nullptr, | ||
| 192 | }; | ||
| 193 | const void* first_next = &features2; | ||
| 194 | void** next = &features2.pNext; | ||
| 195 | |||
| 196 | features2.features = { | ||
| 197 | .robustBufferAccess = false, | ||
| 198 | .fullDrawIndexUint32 = false, | ||
| 199 | .imageCubeArray = false, | ||
| 200 | .independentBlend = true, | ||
| 201 | .geometryShader = true, | ||
| 202 | .tessellationShader = true, | ||
| 203 | .sampleRateShading = false, | ||
| 204 | .dualSrcBlend = false, | ||
| 205 | .logicOp = false, | ||
| 206 | .multiDrawIndirect = false, | ||
| 207 | .drawIndirectFirstInstance = false, | ||
| 208 | .depthClamp = true, | ||
| 209 | .depthBiasClamp = true, | ||
| 210 | .fillModeNonSolid = false, | ||
| 211 | .depthBounds = false, | ||
| 212 | .wideLines = false, | ||
| 213 | .largePoints = true, | ||
| 214 | .alphaToOne = false, | ||
| 215 | .multiViewport = true, | ||
| 216 | .samplerAnisotropy = true, | ||
| 217 | .textureCompressionETC2 = false, | ||
| 218 | .textureCompressionASTC_LDR = is_optimal_astc_supported, | ||
| 219 | .textureCompressionBC = false, | ||
| 220 | .occlusionQueryPrecise = true, | ||
| 221 | .pipelineStatisticsQuery = false, | ||
| 222 | .vertexPipelineStoresAndAtomics = true, | ||
| 223 | .fragmentStoresAndAtomics = true, | ||
| 224 | .shaderTessellationAndGeometryPointSize = false, | ||
| 225 | .shaderImageGatherExtended = true, | ||
| 226 | .shaderStorageImageExtendedFormats = false, | ||
| 227 | .shaderStorageImageMultisample = false, | ||
| 228 | .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, | ||
| 229 | .shaderStorageImageWriteWithoutFormat = true, | ||
| 230 | .shaderUniformBufferArrayDynamicIndexing = false, | ||
| 231 | .shaderSampledImageArrayDynamicIndexing = false, | ||
| 232 | .shaderStorageBufferArrayDynamicIndexing = false, | ||
| 233 | .shaderStorageImageArrayDynamicIndexing = false, | ||
| 234 | .shaderClipDistance = false, | ||
| 235 | .shaderCullDistance = false, | ||
| 236 | .shaderFloat64 = false, | ||
| 237 | .shaderInt64 = false, | ||
| 238 | .shaderInt16 = false, | ||
| 239 | .shaderResourceResidency = false, | ||
| 240 | .shaderResourceMinLod = false, | ||
| 241 | .sparseBinding = false, | ||
| 242 | .sparseResidencyBuffer = false, | ||
| 243 | .sparseResidencyImage2D = false, | ||
| 244 | .sparseResidencyImage3D = false, | ||
| 245 | .sparseResidency2Samples = false, | ||
| 246 | .sparseResidency4Samples = false, | ||
| 247 | .sparseResidency8Samples = false, | ||
| 248 | .sparseResidency16Samples = false, | ||
| 249 | .sparseResidencyAliased = false, | ||
| 250 | .variableMultisampleRate = false, | ||
| 251 | .inheritedQueries = false, | ||
| 252 | }; | ||
| 253 | |||
| 254 | VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{ | ||
| 255 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR, | ||
| 256 | .pNext = nullptr, | ||
| 257 | .timelineSemaphore = true, | ||
| 258 | }; | ||
| 259 | SetNext(next, timeline_semaphore); | ||
| 260 | |||
| 261 | VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{ | ||
| 262 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, | ||
| 263 | .pNext = nullptr, | ||
| 264 | .storageBuffer16BitAccess = false, | ||
| 265 | .uniformAndStorageBuffer16BitAccess = true, | ||
| 266 | .storagePushConstant16 = false, | ||
| 267 | .storageInputOutput16 = false, | ||
| 268 | }; | ||
| 269 | SetNext(next, bit16_storage); | ||
| 270 | |||
| 271 | VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage{ | ||
| 272 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR, | ||
| 273 | .pNext = nullptr, | ||
| 274 | .storageBuffer8BitAccess = false, | ||
| 275 | .uniformAndStorageBuffer8BitAccess = true, | ||
| 276 | .storagePushConstant8 = false, | ||
| 277 | }; | ||
| 278 | SetNext(next, bit8_storage); | ||
| 279 | |||
| 280 | VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ | ||
| 281 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, | ||
| 282 | .hostQueryReset = true, | ||
| 283 | }; | ||
| 284 | SetNext(next, host_query_reset); | ||
| 285 | |||
| 286 | VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8; | ||
| 287 | if (is_float16_supported) { | ||
| 288 | float16_int8 = { | ||
| 289 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR, | ||
| 290 | .pNext = nullptr, | ||
| 291 | .shaderFloat16 = true, | ||
| 292 | .shaderInt8 = false, | ||
| 293 | }; | ||
| 294 | SetNext(next, float16_int8); | ||
| 295 | } else { | ||
| 296 | LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively"); | ||
| 297 | } | ||
| 298 | |||
| 299 | if (!nv_viewport_swizzle) { | ||
| 300 | LOG_INFO(Render_Vulkan, "Device doesn't support viewport swizzles"); | ||
| 301 | } | ||
| 302 | |||
| 303 | VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout; | ||
| 304 | if (khr_uniform_buffer_standard_layout) { | ||
| 305 | std430_layout = { | ||
| 306 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR, | ||
| 307 | .pNext = nullptr, | ||
| 308 | .uniformBufferStandardLayout = true, | ||
| 309 | }; | ||
| 310 | SetNext(next, std430_layout); | ||
| 311 | } else { | ||
| 312 | LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs"); | ||
| 313 | } | ||
| 314 | |||
| 315 | VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8; | ||
| 316 | if (ext_index_type_uint8) { | ||
| 317 | index_type_uint8 = { | ||
| 318 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT, | ||
| 319 | .pNext = nullptr, | ||
| 320 | .indexTypeUint8 = true, | ||
| 321 | }; | ||
| 322 | SetNext(next, index_type_uint8); | ||
| 323 | } else { | ||
| 324 | LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes"); | ||
| 325 | } | ||
| 326 | |||
| 327 | VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback; | ||
| 328 | if (ext_transform_feedback) { | ||
| 329 | transform_feedback = { | ||
| 330 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT, | ||
| 331 | .pNext = nullptr, | ||
| 332 | .transformFeedback = true, | ||
| 333 | .geometryStreams = true, | ||
| 334 | }; | ||
| 335 | SetNext(next, transform_feedback); | ||
| 336 | } else { | ||
| 337 | LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks"); | ||
| 338 | } | ||
| 339 | |||
| 340 | VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border; | ||
| 341 | if (ext_custom_border_color) { | ||
| 342 | custom_border = { | ||
| 343 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT, | ||
| 344 | .pNext = nullptr, | ||
| 345 | .customBorderColors = VK_TRUE, | ||
| 346 | .customBorderColorWithoutFormat = VK_TRUE, | ||
| 347 | }; | ||
| 348 | SetNext(next, custom_border); | ||
| 349 | } else { | ||
| 350 | LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors"); | ||
| 351 | } | ||
| 352 | |||
| 353 | VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state; | ||
| 354 | if (ext_extended_dynamic_state) { | ||
| 355 | dynamic_state = { | ||
| 356 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, | ||
| 357 | .pNext = nullptr, | ||
| 358 | .extendedDynamicState = VK_TRUE, | ||
| 359 | }; | ||
| 360 | SetNext(next, dynamic_state); | ||
| 361 | } else { | ||
| 362 | LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); | ||
| 363 | } | ||
| 364 | |||
| 365 | if (!ext_depth_range_unrestricted) { | ||
| 366 | LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); | ||
| 367 | } | ||
| 368 | |||
| 369 | VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv; | ||
| 370 | if (nv_device_diagnostics_config) { | ||
| 371 | nsight_aftermath_tracker.Initialize(); | ||
| 372 | |||
| 373 | diagnostics_nv = { | ||
| 374 | .sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV, | ||
| 375 | .pNext = &features2, | ||
| 376 | .flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV | | ||
| 377 | VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV | | ||
| 378 | VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV, | ||
| 379 | }; | ||
| 380 | first_next = &diagnostics_nv; | ||
| 381 | } | ||
| 382 | |||
| 383 | logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld); | ||
| 384 | if (!logical) { | ||
| 385 | LOG_ERROR(Render_Vulkan, "Failed to create logical device"); | ||
| 386 | return false; | ||
| 387 | } | ||
| 388 | |||
| 389 | CollectTelemetryParameters(); | ||
| 390 | |||
| 391 | if (ext_extended_dynamic_state && driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR) { | ||
| 392 | // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but the <stride> field | ||
| 393 | // seems to be bugged. Blacklisting it for now. | ||
| 394 | LOG_WARNING(Render_Vulkan, | ||
| 395 | "Blacklisting AMD proprietary from VK_EXT_extended_dynamic_state"); | ||
| 396 | ext_extended_dynamic_state = false; | ||
| 397 | } | ||
| 398 | |||
| 399 | graphics_queue = logical.GetQueue(graphics_family); | ||
| 400 | present_queue = logical.GetQueue(present_family); | ||
| 401 | |||
| 402 | use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); | ||
| 403 | return true; | ||
| 404 | } | ||
| 405 | |||
| 406 | VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, | ||
| 407 | FormatType format_type) const { | ||
| 408 | if (IsFormatSupported(wanted_format, wanted_usage, format_type)) { | ||
| 409 | return wanted_format; | ||
| 410 | } | ||
| 411 | // The wanted format is not supported by hardware, search for alternatives | ||
| 412 | const VkFormat* alternatives = GetFormatAlternatives(wanted_format); | ||
| 413 | if (alternatives == nullptr) { | ||
| 414 | UNREACHABLE_MSG("Format={} with usage={} and type={} has no defined alternatives and host " | ||
| 415 | "hardware does not support it", | ||
| 416 | wanted_format, wanted_usage, format_type); | ||
| 417 | return wanted_format; | ||
| 418 | } | ||
| 419 | |||
| 420 | std::size_t i = 0; | ||
| 421 | for (VkFormat alternative = *alternatives; alternative; alternative = alternatives[++i]) { | ||
| 422 | if (!IsFormatSupported(alternative, wanted_usage, format_type)) { | ||
| 423 | continue; | ||
| 424 | } | ||
| 425 | LOG_WARNING(Render_Vulkan, | ||
| 426 | "Emulating format={} with alternative format={} with usage={} and type={}", | ||
| 427 | wanted_format, alternative, wanted_usage, format_type); | ||
| 428 | return alternative; | ||
| 429 | } | ||
| 430 | |||
| 431 | // No alternatives found, panic | ||
| 432 | UNREACHABLE_MSG("Format={} with usage={} and type={} is not supported by the host hardware and " | ||
| 433 | "doesn't support any of the alternatives", | ||
| 434 | wanted_format, wanted_usage, format_type); | ||
| 435 | return wanted_format; | ||
| 436 | } | ||
| 437 | |||
| 438 | void VKDevice::ReportLoss() const { | ||
| 439 | LOG_CRITICAL(Render_Vulkan, "Device loss occured!"); | ||
| 440 | |||
| 441 | // Wait for the log to flush and for Nsight Aftermath to dump the results | ||
| 442 | std::this_thread::sleep_for(std::chrono::seconds{3}); | ||
| 443 | } | ||
| 444 | |||
| 445 | void VKDevice::SaveShader(const std::vector<u32>& spirv) const { | ||
| 446 | nsight_aftermath_tracker.SaveShader(spirv); | ||
| 447 | } | ||
| 448 | |||
| 449 | bool VKDevice::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const { | ||
| 450 | // Disable for now to avoid converting ASTC twice. | ||
| 451 | static constexpr std::array astc_formats = { | ||
| 452 | VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK, | ||
| 453 | VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_ASTC_5x4_SRGB_BLOCK, | ||
| 454 | VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_ASTC_5x5_SRGB_BLOCK, | ||
| 455 | VK_FORMAT_ASTC_6x5_UNORM_BLOCK, VK_FORMAT_ASTC_6x5_SRGB_BLOCK, | ||
| 456 | VK_FORMAT_ASTC_6x6_UNORM_BLOCK, VK_FORMAT_ASTC_6x6_SRGB_BLOCK, | ||
| 457 | VK_FORMAT_ASTC_8x5_UNORM_BLOCK, VK_FORMAT_ASTC_8x5_SRGB_BLOCK, | ||
| 458 | VK_FORMAT_ASTC_8x6_UNORM_BLOCK, VK_FORMAT_ASTC_8x6_SRGB_BLOCK, | ||
| 459 | VK_FORMAT_ASTC_8x8_UNORM_BLOCK, VK_FORMAT_ASTC_8x8_SRGB_BLOCK, | ||
| 460 | VK_FORMAT_ASTC_10x5_UNORM_BLOCK, VK_FORMAT_ASTC_10x5_SRGB_BLOCK, | ||
| 461 | VK_FORMAT_ASTC_10x6_UNORM_BLOCK, VK_FORMAT_ASTC_10x6_SRGB_BLOCK, | ||
| 462 | VK_FORMAT_ASTC_10x8_UNORM_BLOCK, VK_FORMAT_ASTC_10x8_SRGB_BLOCK, | ||
| 463 | VK_FORMAT_ASTC_10x10_UNORM_BLOCK, VK_FORMAT_ASTC_10x10_SRGB_BLOCK, | ||
| 464 | VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_ASTC_12x10_SRGB_BLOCK, | ||
| 465 | VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_ASTC_12x12_SRGB_BLOCK, | ||
| 466 | }; | ||
| 467 | if (!features.textureCompressionASTC_LDR) { | ||
| 468 | return false; | ||
| 469 | } | ||
| 470 | const auto format_feature_usage{ | ||
| 471 | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT | | ||
| 472 | VK_FORMAT_FEATURE_BLIT_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | | ||
| 473 | VK_FORMAT_FEATURE_TRANSFER_DST_BIT}; | ||
| 474 | for (const auto format : astc_formats) { | ||
| 475 | const auto format_properties{physical.GetFormatProperties(format)}; | ||
| 476 | if (!(format_properties.optimalTilingFeatures & format_feature_usage)) { | ||
| 477 | return false; | ||
| 478 | } | ||
| 479 | } | ||
| 480 | return true; | ||
| 481 | } | ||
| 482 | |||
| 483 | bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, | ||
| 484 | FormatType format_type) const { | ||
| 485 | const auto it = format_properties.find(wanted_format); | ||
| 486 | if (it == format_properties.end()) { | ||
| 487 | UNIMPLEMENTED_MSG("Unimplemented format query={}", wanted_format); | ||
| 488 | return true; | ||
| 489 | } | ||
| 490 | const auto supported_usage = GetFormatFeatures(it->second, format_type); | ||
| 491 | return (supported_usage & wanted_usage) == wanted_usage; | ||
| 492 | } | ||
| 493 | |||
| 494 | bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { | ||
| 495 | bool is_suitable = true; | ||
| 496 | std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; | ||
| 497 | |||
| 498 | for (const auto& prop : physical.EnumerateDeviceExtensionProperties()) { | ||
| 499 | for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { | ||
| 500 | if (available_extensions[i]) { | ||
| 501 | continue; | ||
| 502 | } | ||
| 503 | const std::string_view name{prop.extensionName}; | ||
| 504 | available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; | ||
| 505 | } | ||
| 506 | } | ||
| 507 | if (!available_extensions.all()) { | ||
| 508 | for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { | ||
| 509 | if (available_extensions[i]) { | ||
| 510 | continue; | ||
| 511 | } | ||
| 512 | LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); | ||
| 513 | is_suitable = false; | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | bool has_graphics{}, has_present{}; | ||
| 518 | const std::vector queue_family_properties = physical.GetQueueFamilyProperties(); | ||
| 519 | for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { | ||
| 520 | const auto& family = queue_family_properties[i]; | ||
| 521 | if (family.queueCount == 0) { | ||
| 522 | continue; | ||
| 523 | } | ||
| 524 | has_graphics |= family.queueFlags & VK_QUEUE_GRAPHICS_BIT; | ||
| 525 | has_present |= physical.GetSurfaceSupportKHR(i, surface); | ||
| 526 | } | ||
| 527 | if (!has_graphics || !has_present) { | ||
| 528 | LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue"); | ||
| 529 | is_suitable = false; | ||
| 530 | } | ||
| 531 | |||
| 532 | // TODO(Rodrigo): Check if the device matches all requeriments. | ||
| 533 | const auto properties{physical.GetProperties()}; | ||
| 534 | const auto& limits{properties.limits}; | ||
| 535 | |||
| 536 | constexpr u32 required_ubo_size = 65536; | ||
| 537 | if (limits.maxUniformBufferRange < required_ubo_size) { | ||
| 538 | LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required", | ||
| 539 | limits.maxUniformBufferRange, required_ubo_size); | ||
| 540 | is_suitable = false; | ||
| 541 | } | ||
| 542 | |||
| 543 | constexpr u32 required_num_viewports = 16; | ||
| 544 | if (limits.maxViewports < required_num_viewports) { | ||
| 545 | LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required", | ||
| 546 | limits.maxViewports, required_num_viewports); | ||
| 547 | is_suitable = false; | ||
| 548 | } | ||
| 549 | |||
| 550 | const auto features{physical.GetFeatures()}; | ||
| 551 | const std::array feature_report = { | ||
| 552 | std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), | ||
| 553 | std::make_pair(features.independentBlend, "independentBlend"), | ||
| 554 | std::make_pair(features.depthClamp, "depthClamp"), | ||
| 555 | std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"), | ||
| 556 | std::make_pair(features.largePoints, "largePoints"), | ||
| 557 | std::make_pair(features.multiViewport, "multiViewport"), | ||
| 558 | std::make_pair(features.depthBiasClamp, "depthBiasClamp"), | ||
| 559 | std::make_pair(features.geometryShader, "geometryShader"), | ||
| 560 | std::make_pair(features.tessellationShader, "tessellationShader"), | ||
| 561 | std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), | ||
| 562 | std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"), | ||
| 563 | std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), | ||
| 564 | std::make_pair(features.shaderStorageImageWriteWithoutFormat, | ||
| 565 | "shaderStorageImageWriteWithoutFormat"), | ||
| 566 | }; | ||
| 567 | for (const auto& [supported, name] : feature_report) { | ||
| 568 | if (supported) { | ||
| 569 | continue; | ||
| 570 | } | ||
| 571 | LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); | ||
| 572 | is_suitable = false; | ||
| 573 | } | ||
| 574 | |||
| 575 | if (!is_suitable) { | ||
| 576 | LOG_ERROR(Render_Vulkan, "{} is not suitable", properties.deviceName); | ||
| 577 | } | ||
| 578 | |||
| 579 | return is_suitable; | ||
| 580 | } | ||
| 581 | |||
| 582 | std::vector<const char*> VKDevice::LoadExtensions() { | ||
| 583 | std::vector<const char*> extensions; | ||
| 584 | const auto Test = [&](const VkExtensionProperties& extension, | ||
| 585 | std::optional<std::reference_wrapper<bool>> status, const char* name, | ||
| 586 | bool push) { | ||
| 587 | if (extension.extensionName != std::string_view(name)) { | ||
| 588 | return; | ||
| 589 | } | ||
| 590 | if (push) { | ||
| 591 | extensions.push_back(name); | ||
| 592 | } | ||
| 593 | if (status) { | ||
| 594 | status->get() = true; | ||
| 595 | } | ||
| 596 | }; | ||
| 597 | |||
| 598 | extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); | ||
| 599 | extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); | ||
| 600 | |||
| 601 | bool has_khr_shader_float16_int8{}; | ||
| 602 | bool has_ext_subgroup_size_control{}; | ||
| 603 | bool has_ext_transform_feedback{}; | ||
| 604 | bool has_ext_custom_border_color{}; | ||
| 605 | bool has_ext_extended_dynamic_state{}; | ||
| 606 | for (const auto& extension : physical.EnumerateDeviceExtensionProperties()) { | ||
| 607 | Test(extension, nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true); | ||
| 608 | Test(extension, khr_uniform_buffer_standard_layout, | ||
| 609 | VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true); | ||
| 610 | Test(extension, has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, | ||
| 611 | false); | ||
| 612 | Test(extension, ext_depth_range_unrestricted, | ||
| 613 | VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); | ||
| 614 | Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); | ||
| 615 | Test(extension, ext_shader_viewport_index_layer, | ||
| 616 | VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, true); | ||
| 617 | Test(extension, has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, | ||
| 618 | false); | ||
| 619 | Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, | ||
| 620 | false); | ||
| 621 | Test(extension, has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, | ||
| 622 | false); | ||
| 623 | Test(extension, has_ext_extended_dynamic_state, | ||
| 624 | VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); | ||
| 625 | if (Settings::values.renderer_debug) { | ||
| 626 | Test(extension, nv_device_diagnostics_config, | ||
| 627 | VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true); | ||
| 628 | } | ||
| 629 | } | ||
| 630 | |||
| 631 | VkPhysicalDeviceFeatures2KHR features; | ||
| 632 | features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; | ||
| 633 | |||
| 634 | VkPhysicalDeviceProperties2KHR properties; | ||
| 635 | properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; | ||
| 636 | |||
| 637 | if (has_khr_shader_float16_int8) { | ||
| 638 | VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8_features; | ||
| 639 | float16_int8_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; | ||
| 640 | float16_int8_features.pNext = nullptr; | ||
| 641 | features.pNext = &float16_int8_features; | ||
| 642 | |||
| 643 | physical.GetFeatures2KHR(features); | ||
| 644 | is_float16_supported = float16_int8_features.shaderFloat16; | ||
| 645 | extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); | ||
| 646 | } | ||
| 647 | |||
| 648 | if (has_ext_subgroup_size_control) { | ||
| 649 | VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroup_features; | ||
| 650 | subgroup_features.sType = | ||
| 651 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT; | ||
| 652 | subgroup_features.pNext = nullptr; | ||
| 653 | features.pNext = &subgroup_features; | ||
| 654 | physical.GetFeatures2KHR(features); | ||
| 655 | |||
| 656 | VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_properties; | ||
| 657 | subgroup_properties.sType = | ||
| 658 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT; | ||
| 659 | subgroup_properties.pNext = nullptr; | ||
| 660 | properties.pNext = &subgroup_properties; | ||
| 661 | physical.GetProperties2KHR(properties); | ||
| 662 | |||
| 663 | is_warp_potentially_bigger = subgroup_properties.maxSubgroupSize > GuestWarpSize; | ||
| 664 | |||
| 665 | if (subgroup_features.subgroupSizeControl && | ||
| 666 | subgroup_properties.minSubgroupSize <= GuestWarpSize && | ||
| 667 | subgroup_properties.maxSubgroupSize >= GuestWarpSize) { | ||
| 668 | extensions.push_back(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME); | ||
| 669 | guest_warp_stages = subgroup_properties.requiredSubgroupSizeStages; | ||
| 670 | } | ||
| 671 | } else { | ||
| 672 | is_warp_potentially_bigger = true; | ||
| 673 | } | ||
| 674 | |||
| 675 | if (has_ext_transform_feedback) { | ||
| 676 | VkPhysicalDeviceTransformFeedbackFeaturesEXT tfb_features; | ||
| 677 | tfb_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; | ||
| 678 | tfb_features.pNext = nullptr; | ||
| 679 | features.pNext = &tfb_features; | ||
| 680 | physical.GetFeatures2KHR(features); | ||
| 681 | |||
| 682 | VkPhysicalDeviceTransformFeedbackPropertiesEXT tfb_properties; | ||
| 683 | tfb_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT; | ||
| 684 | tfb_properties.pNext = nullptr; | ||
| 685 | properties.pNext = &tfb_properties; | ||
| 686 | physical.GetProperties2KHR(properties); | ||
| 687 | |||
| 688 | if (tfb_features.transformFeedback && tfb_features.geometryStreams && | ||
| 689 | tfb_properties.maxTransformFeedbackStreams >= 4 && | ||
| 690 | tfb_properties.maxTransformFeedbackBuffers && tfb_properties.transformFeedbackQueries && | ||
| 691 | tfb_properties.transformFeedbackDraw) { | ||
| 692 | extensions.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); | ||
| 693 | ext_transform_feedback = true; | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | if (has_ext_custom_border_color) { | ||
| 698 | VkPhysicalDeviceCustomBorderColorFeaturesEXT border_features; | ||
| 699 | border_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; | ||
| 700 | border_features.pNext = nullptr; | ||
| 701 | features.pNext = &border_features; | ||
| 702 | physical.GetFeatures2KHR(features); | ||
| 703 | |||
| 704 | if (border_features.customBorderColors && border_features.customBorderColorWithoutFormat) { | ||
| 705 | extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); | ||
| 706 | ext_custom_border_color = true; | ||
| 707 | } | ||
| 708 | } | ||
| 709 | |||
| 710 | if (has_ext_extended_dynamic_state) { | ||
| 711 | VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state; | ||
| 712 | dynamic_state.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; | ||
| 713 | dynamic_state.pNext = nullptr; | ||
| 714 | features.pNext = &dynamic_state; | ||
| 715 | physical.GetFeatures2KHR(features); | ||
| 716 | |||
| 717 | if (dynamic_state.extendedDynamicState) { | ||
| 718 | extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); | ||
| 719 | ext_extended_dynamic_state = true; | ||
| 720 | } | ||
| 721 | } | ||
| 722 | |||
| 723 | return extensions; | ||
| 724 | } | ||
| 725 | |||
| 726 | void VKDevice::SetupFamilies(VkSurfaceKHR surface) { | ||
| 727 | std::optional<u32> graphics_family_, present_family_; | ||
| 728 | |||
| 729 | const std::vector queue_family_properties = physical.GetQueueFamilyProperties(); | ||
| 730 | for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { | ||
| 731 | if (graphics_family_ && present_family_) | ||
| 732 | break; | ||
| 733 | |||
| 734 | const auto& queue_family = queue_family_properties[i]; | ||
| 735 | if (queue_family.queueCount == 0) | ||
| 736 | continue; | ||
| 737 | |||
| 738 | if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { | ||
| 739 | graphics_family_ = i; | ||
| 740 | } | ||
| 741 | if (physical.GetSurfaceSupportKHR(i, surface)) { | ||
| 742 | present_family_ = i; | ||
| 743 | } | ||
| 744 | } | ||
| 745 | ASSERT(graphics_family_ && present_family_); | ||
| 746 | |||
| 747 | graphics_family = *graphics_family_; | ||
| 748 | present_family = *present_family_; | ||
| 749 | } | ||
| 750 | |||
| 751 | void VKDevice::SetupFeatures() { | ||
| 752 | const auto supported_features{physical.GetFeatures()}; | ||
| 753 | is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; | ||
| 754 | is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); | ||
| 755 | } | ||
| 756 | |||
| 757 | void VKDevice::CollectTelemetryParameters() { | ||
| 758 | VkPhysicalDeviceDriverPropertiesKHR driver{ | ||
| 759 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, | ||
| 760 | .pNext = nullptr, | ||
| 761 | }; | ||
| 762 | |||
| 763 | VkPhysicalDeviceProperties2KHR properties{ | ||
| 764 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, | ||
| 765 | .pNext = &driver, | ||
| 766 | }; | ||
| 767 | physical.GetProperties2KHR(properties); | ||
| 768 | |||
| 769 | driver_id = driver.driverID; | ||
| 770 | vendor_name = driver.driverName; | ||
| 771 | |||
| 772 | const std::vector extensions = physical.EnumerateDeviceExtensionProperties(); | ||
| 773 | reported_extensions.reserve(std::size(extensions)); | ||
| 774 | for (const auto& extension : extensions) { | ||
| 775 | reported_extensions.emplace_back(extension.extensionName); | ||
| 776 | } | ||
| 777 | } | ||
| 778 | |||
| 779 | std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { | ||
| 780 | static constexpr float QUEUE_PRIORITY = 1.0f; | ||
| 781 | |||
| 782 | std::unordered_set<u32> unique_queue_families{graphics_family, present_family}; | ||
| 783 | std::vector<VkDeviceQueueCreateInfo> queue_cis; | ||
| 784 | queue_cis.reserve(unique_queue_families.size()); | ||
| 785 | |||
| 786 | for (const u32 queue_family : unique_queue_families) { | ||
| 787 | auto& ci = queue_cis.emplace_back(VkDeviceQueueCreateInfo{ | ||
| 788 | .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, | ||
| 789 | .pNext = nullptr, | ||
| 790 | .flags = 0, | ||
| 791 | .queueFamilyIndex = queue_family, | ||
| 792 | .queueCount = 1, | ||
| 793 | .pQueuePriorities = nullptr, | ||
| 794 | }); | ||
| 795 | ci.pQueuePriorities = &QUEUE_PRIORITY; | ||
| 796 | } | ||
| 797 | |||
| 798 | return queue_cis; | ||
| 799 | } | ||
| 800 | |||
| 801 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h deleted file mode 100644 index 26a233db1..000000000 --- a/src/video_core/renderer_vulkan/vk_device.h +++ /dev/null | |||
| @@ -1,274 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | #include <string_view> | ||
| 9 | #include <unordered_map> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "video_core/renderer_vulkan/nsight_aftermath_tracker.h" | ||
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 15 | |||
| 16 | namespace Vulkan { | ||
| 17 | |||
| 18 | /// Format usage descriptor. | ||
| 19 | enum class FormatType { Linear, Optimal, Buffer }; | ||
| 20 | |||
| 21 | /// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup). | ||
| 22 | const u32 GuestWarpSize = 32; | ||
| 23 | |||
| 24 | /// Handles data specific to a physical device. | ||
| 25 | class VKDevice final { | ||
| 26 | public: | ||
| 27 | explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, | ||
| 28 | const vk::InstanceDispatch& dld); | ||
| 29 | ~VKDevice(); | ||
| 30 | |||
| 31 | /// Initializes the device. Returns true on success. | ||
| 32 | bool Create(); | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Returns a format supported by the device for the passed requeriments. | ||
| 36 | * @param wanted_format The ideal format to be returned. It may not be the returned format. | ||
| 37 | * @param wanted_usage The usage that must be fulfilled even if the format is not supported. | ||
| 38 | * @param format_type Format type usage. | ||
| 39 | * @returns A format supported by the device. | ||
| 40 | */ | ||
| 41 | VkFormat GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, | ||
| 42 | FormatType format_type) const; | ||
| 43 | |||
| 44 | /// Reports a device loss. | ||
| 45 | void ReportLoss() const; | ||
| 46 | |||
| 47 | /// Reports a shader to Nsight Aftermath. | ||
| 48 | void SaveShader(const std::vector<u32>& spirv) const; | ||
| 49 | |||
| 50 | /// Returns the dispatch loader with direct function pointers of the device. | ||
| 51 | const vk::DeviceDispatch& GetDispatchLoader() const { | ||
| 52 | return dld; | ||
| 53 | } | ||
| 54 | |||
| 55 | /// Returns the logical device. | ||
| 56 | const vk::Device& GetLogical() const { | ||
| 57 | return logical; | ||
| 58 | } | ||
| 59 | |||
| 60 | /// Returns the physical device. | ||
| 61 | vk::PhysicalDevice GetPhysical() const { | ||
| 62 | return physical; | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Returns the main graphics queue. | ||
| 66 | vk::Queue GetGraphicsQueue() const { | ||
| 67 | return graphics_queue; | ||
| 68 | } | ||
| 69 | |||
| 70 | /// Returns the main present queue. | ||
| 71 | vk::Queue GetPresentQueue() const { | ||
| 72 | return present_queue; | ||
| 73 | } | ||
| 74 | |||
| 75 | /// Returns main graphics queue family index. | ||
| 76 | u32 GetGraphicsFamily() const { | ||
| 77 | return graphics_family; | ||
| 78 | } | ||
| 79 | |||
| 80 | /// Returns main present queue family index. | ||
| 81 | u32 GetPresentFamily() const { | ||
| 82 | return present_family; | ||
| 83 | } | ||
| 84 | |||
| 85 | /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. | ||
| 86 | u32 GetApiVersion() const { | ||
| 87 | return properties.apiVersion; | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Returns the current driver version provided in Vulkan-formatted version numbers. | ||
| 91 | u32 GetDriverVersion() const { | ||
| 92 | return properties.driverVersion; | ||
| 93 | } | ||
| 94 | |||
| 95 | /// Returns the device name. | ||
| 96 | std::string_view GetModelName() const { | ||
| 97 | return properties.deviceName; | ||
| 98 | } | ||
| 99 | |||
| 100 | /// Returns the driver ID. | ||
| 101 | VkDriverIdKHR GetDriverID() const { | ||
| 102 | return driver_id; | ||
| 103 | } | ||
| 104 | |||
| 105 | /// Returns uniform buffer alignment requeriment. | ||
| 106 | VkDeviceSize GetUniformBufferAlignment() const { | ||
| 107 | return properties.limits.minUniformBufferOffsetAlignment; | ||
| 108 | } | ||
| 109 | |||
| 110 | /// Returns storage alignment requeriment. | ||
| 111 | VkDeviceSize GetStorageBufferAlignment() const { | ||
| 112 | return properties.limits.minStorageBufferOffsetAlignment; | ||
| 113 | } | ||
| 114 | |||
| 115 | /// Returns the maximum range for storage buffers. | ||
| 116 | VkDeviceSize GetMaxStorageBufferRange() const { | ||
| 117 | return properties.limits.maxStorageBufferRange; | ||
| 118 | } | ||
| 119 | |||
| 120 | /// Returns the maximum size for push constants. | ||
| 121 | VkDeviceSize GetMaxPushConstantsSize() const { | ||
| 122 | return properties.limits.maxPushConstantsSize; | ||
| 123 | } | ||
| 124 | |||
| 125 | /// Returns the maximum size for shared memory. | ||
| 126 | u32 GetMaxComputeSharedMemorySize() const { | ||
| 127 | return properties.limits.maxComputeSharedMemorySize; | ||
| 128 | } | ||
| 129 | |||
| 130 | /// Returns true if ASTC is natively supported. | ||
| 131 | bool IsOptimalAstcSupported() const { | ||
| 132 | return is_optimal_astc_supported; | ||
| 133 | } | ||
| 134 | |||
| 135 | /// Returns true if the device supports float16 natively | ||
| 136 | bool IsFloat16Supported() const { | ||
| 137 | return is_float16_supported; | ||
| 138 | } | ||
| 139 | |||
| 140 | /// Returns true if the device warp size can potentially be bigger than guest's warp size. | ||
| 141 | bool IsWarpSizePotentiallyBiggerThanGuest() const { | ||
| 142 | return is_warp_potentially_bigger; | ||
| 143 | } | ||
| 144 | |||
| 145 | /// Returns true if the device can be forced to use the guest warp size. | ||
| 146 | bool IsGuestWarpSizeSupported(VkShaderStageFlagBits stage) const { | ||
| 147 | return guest_warp_stages & stage; | ||
| 148 | } | ||
| 149 | |||
| 150 | /// Returns true if formatless image load is supported. | ||
| 151 | bool IsFormatlessImageLoadSupported() const { | ||
| 152 | return is_formatless_image_load_supported; | ||
| 153 | } | ||
| 154 | |||
| 155 | /// Returns true if the device supports VK_NV_viewport_swizzle. | ||
| 156 | bool IsNvViewportSwizzleSupported() const { | ||
| 157 | return nv_viewport_swizzle; | ||
| 158 | } | ||
| 159 | |||
| 160 | /// Returns true if the device supports VK_EXT_scalar_block_layout. | ||
| 161 | bool IsKhrUniformBufferStandardLayoutSupported() const { | ||
| 162 | return khr_uniform_buffer_standard_layout; | ||
| 163 | } | ||
| 164 | |||
| 165 | /// Returns true if the device supports VK_EXT_index_type_uint8. | ||
| 166 | bool IsExtIndexTypeUint8Supported() const { | ||
| 167 | return ext_index_type_uint8; | ||
| 168 | } | ||
| 169 | |||
| 170 | /// Returns true if the device supports VK_EXT_depth_range_unrestricted. | ||
| 171 | bool IsExtDepthRangeUnrestrictedSupported() const { | ||
| 172 | return ext_depth_range_unrestricted; | ||
| 173 | } | ||
| 174 | |||
| 175 | /// Returns true if the device supports VK_EXT_shader_viewport_index_layer. | ||
| 176 | bool IsExtShaderViewportIndexLayerSupported() const { | ||
| 177 | return ext_shader_viewport_index_layer; | ||
| 178 | } | ||
| 179 | |||
| 180 | /// Returns true if the device supports VK_EXT_transform_feedback. | ||
| 181 | bool IsExtTransformFeedbackSupported() const { | ||
| 182 | return ext_transform_feedback; | ||
| 183 | } | ||
| 184 | |||
| 185 | /// Returns true if the device supports VK_EXT_custom_border_color. | ||
| 186 | bool IsExtCustomBorderColorSupported() const { | ||
| 187 | return ext_custom_border_color; | ||
| 188 | } | ||
| 189 | |||
| 190 | /// Returns true if the device supports VK_EXT_extended_dynamic_state. | ||
| 191 | bool IsExtExtendedDynamicStateSupported() const { | ||
| 192 | return ext_extended_dynamic_state; | ||
| 193 | } | ||
| 194 | |||
| 195 | /// Returns the vendor name reported from Vulkan. | ||
| 196 | std::string_view GetVendorName() const { | ||
| 197 | return vendor_name; | ||
| 198 | } | ||
| 199 | |||
| 200 | /// Returns the list of available extensions. | ||
| 201 | const std::vector<std::string>& GetAvailableExtensions() const { | ||
| 202 | return reported_extensions; | ||
| 203 | } | ||
| 204 | |||
| 205 | /// Returns true if the setting for async shader compilation is enabled. | ||
| 206 | bool UseAsynchronousShaders() const { | ||
| 207 | return use_asynchronous_shaders; | ||
| 208 | } | ||
| 209 | |||
| 210 | /// Checks if the physical device is suitable. | ||
| 211 | static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface); | ||
| 212 | |||
| 213 | private: | ||
| 214 | /// Loads extensions into a vector and stores available ones in this object. | ||
| 215 | std::vector<const char*> LoadExtensions(); | ||
| 216 | |||
| 217 | /// Sets up queue families. | ||
| 218 | void SetupFamilies(VkSurfaceKHR surface); | ||
| 219 | |||
| 220 | /// Sets up device features. | ||
| 221 | void SetupFeatures(); | ||
| 222 | |||
| 223 | /// Collects telemetry information from the device. | ||
| 224 | void CollectTelemetryParameters(); | ||
| 225 | |||
| 226 | /// Returns a list of queue initialization descriptors. | ||
| 227 | std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const; | ||
| 228 | |||
| 229 | /// Returns true if ASTC textures are natively supported. | ||
| 230 | bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const; | ||
| 231 | |||
| 232 | /// Returns true if a format is supported. | ||
| 233 | bool IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, | ||
| 234 | FormatType format_type) const; | ||
| 235 | |||
| 236 | vk::DeviceDispatch dld; ///< Device function pointers. | ||
| 237 | vk::PhysicalDevice physical; ///< Physical device. | ||
| 238 | VkPhysicalDeviceProperties properties; ///< Device properties. | ||
| 239 | vk::Device logical; ///< Logical device. | ||
| 240 | vk::Queue graphics_queue; ///< Main graphics queue. | ||
| 241 | vk::Queue present_queue; ///< Main present queue. | ||
| 242 | u32 graphics_family{}; ///< Main graphics queue family index. | ||
| 243 | u32 present_family{}; ///< Main present queue family index. | ||
| 244 | VkDriverIdKHR driver_id{}; ///< Driver ID. | ||
| 245 | VkShaderStageFlags guest_warp_stages{}; ///< Stages where the guest warp size can be forced.ed | ||
| 246 | bool is_optimal_astc_supported{}; ///< Support for native ASTC. | ||
| 247 | bool is_float16_supported{}; ///< Support for float16 arithmetics. | ||
| 248 | bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. | ||
| 249 | bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. | ||
| 250 | bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. | ||
| 251 | bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs. | ||
| 252 | bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. | ||
| 253 | bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. | ||
| 254 | bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. | ||
| 255 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. | ||
| 256 | bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. | ||
| 257 | bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. | ||
| 258 | bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. | ||
| 259 | |||
| 260 | // Asynchronous Graphics Pipeline setting | ||
| 261 | bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline | ||
| 262 | |||
| 263 | // Telemetry parameters | ||
| 264 | std::string vendor_name; ///< Device's driver name. | ||
| 265 | std::vector<std::string> reported_extensions; ///< Reported Vulkan extensions. | ||
| 266 | |||
| 267 | /// Format properties dictionary. | ||
| 268 | std::unordered_map<VkFormat, VkFormatProperties> format_properties; | ||
| 269 | |||
| 270 | /// Nsight Aftermath GPU crash tracker | ||
| 271 | NsightAftermathTracker nsight_aftermath_tracker; | ||
| 272 | }; | ||
| 273 | |||
| 274 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp index 5babbdd0b..4c5bc0aa1 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp | |||
| @@ -6,20 +6,21 @@ | |||
| 6 | #include <thread> | 6 | #include <thread> |
| 7 | 7 | ||
| 8 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 8 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_fence_manager.h" | 9 | #include "video_core/renderer_vulkan/vk_fence_manager.h" |
| 11 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 10 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 12 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 11 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 13 | #include "video_core/renderer_vulkan/wrapper.h" | 12 | #include "video_core/vulkan_common/vulkan_device.h" |
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 14 | 14 | ||
| 15 | namespace Vulkan { | 15 | namespace Vulkan { |
| 16 | 16 | ||
| 17 | InnerFence::InnerFence(const VKDevice& device, VKScheduler& scheduler, u32 payload, bool is_stubbed) | 17 | InnerFence::InnerFence(const Device& device_, VKScheduler& scheduler_, u32 payload_, |
| 18 | : VideoCommon::FenceBase(payload, is_stubbed), device{device}, scheduler{scheduler} {} | 18 | bool is_stubbed_) |
| 19 | : FenceBase{payload_, is_stubbed_}, device{device_}, scheduler{scheduler_} {} | ||
| 19 | 20 | ||
| 20 | InnerFence::InnerFence(const VKDevice& device, VKScheduler& scheduler, GPUVAddr address, | 21 | InnerFence::InnerFence(const Device& device_, VKScheduler& scheduler_, GPUVAddr address_, |
| 21 | u32 payload, bool is_stubbed) | 22 | u32 payload_, bool is_stubbed_) |
| 22 | : VideoCommon::FenceBase(address, payload, is_stubbed), device{device}, scheduler{scheduler} {} | 23 | : FenceBase{address_, payload_, is_stubbed_}, device{device_}, scheduler{scheduler_} {} |
| 23 | 24 | ||
| 24 | InnerFence::~InnerFence() = default; | 25 | InnerFence::~InnerFence() = default; |
| 25 | 26 | ||
| @@ -71,11 +72,11 @@ bool InnerFence::IsEventSignalled() const { | |||
| 71 | } | 72 | } |
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu, | 75 | VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, |
| 75 | Tegra::MemoryManager& memory_manager, VKTextureCache& texture_cache, | 76 | Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, |
| 76 | VKBufferCache& buffer_cache, VKQueryCache& query_cache, | 77 | VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, |
| 77 | const VKDevice& device_, VKScheduler& scheduler_) | 78 | const Device& device_, VKScheduler& scheduler_) |
| 78 | : GenericFenceManager(rasterizer, gpu, texture_cache, buffer_cache, query_cache), | 79 | : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, |
| 79 | device{device_}, scheduler{scheduler_} {} | 80 | device{device_}, scheduler{scheduler_} {} |
| 80 | 81 | ||
| 81 | Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) { | 82 | Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) { |
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h index 1547d6d30..6b51e4587 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.h +++ b/src/video_core/renderer_vulkan/vk_fence_manager.h | |||
| @@ -8,7 +8,8 @@ | |||
| 8 | 8 | ||
| 9 | #include "video_core/fence_manager.h" | 9 | #include "video_core/fence_manager.h" |
| 10 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 10 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | 11 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 12 | 13 | ||
| 13 | namespace Core { | 14 | namespace Core { |
| 14 | class System; | 15 | class System; |
| @@ -20,18 +21,17 @@ class RasterizerInterface; | |||
| 20 | 21 | ||
| 21 | namespace Vulkan { | 22 | namespace Vulkan { |
| 22 | 23 | ||
| 24 | class Device; | ||
| 23 | class VKBufferCache; | 25 | class VKBufferCache; |
| 24 | class VKDevice; | ||
| 25 | class VKQueryCache; | 26 | class VKQueryCache; |
| 26 | class VKScheduler; | 27 | class VKScheduler; |
| 27 | class VKTextureCache; | ||
| 28 | 28 | ||
| 29 | class InnerFence : public VideoCommon::FenceBase { | 29 | class InnerFence : public VideoCommon::FenceBase { |
| 30 | public: | 30 | public: |
| 31 | explicit InnerFence(const VKDevice& device, VKScheduler& scheduler, u32 payload, | 31 | explicit InnerFence(const Device& device_, VKScheduler& scheduler_, u32 payload_, |
| 32 | bool is_stubbed); | 32 | bool is_stubbed_); |
| 33 | explicit InnerFence(const VKDevice& device, VKScheduler& scheduler, GPUVAddr address, | 33 | explicit InnerFence(const Device& device_, VKScheduler& scheduler_, GPUVAddr address_, |
| 34 | u32 payload, bool is_stubbed); | 34 | u32 payload_, bool is_stubbed_); |
| 35 | ~InnerFence(); | 35 | ~InnerFence(); |
| 36 | 36 | ||
| 37 | void Queue(); | 37 | void Queue(); |
| @@ -43,7 +43,7 @@ public: | |||
| 43 | private: | 43 | private: |
| 44 | bool IsEventSignalled() const; | 44 | bool IsEventSignalled() const; |
| 45 | 45 | ||
| 46 | const VKDevice& device; | 46 | const Device& device; |
| 47 | VKScheduler& scheduler; | 47 | VKScheduler& scheduler; |
| 48 | vk::Event event; | 48 | vk::Event event; |
| 49 | u64 ticks = 0; | 49 | u64 ticks = 0; |
| @@ -51,14 +51,14 @@ private: | |||
| 51 | using Fence = std::shared_ptr<InnerFence>; | 51 | using Fence = std::shared_ptr<InnerFence>; |
| 52 | 52 | ||
| 53 | using GenericFenceManager = | 53 | using GenericFenceManager = |
| 54 | VideoCommon::FenceManager<Fence, VKTextureCache, VKBufferCache, VKQueryCache>; | 54 | VideoCommon::FenceManager<Fence, TextureCache, VKBufferCache, VKQueryCache>; |
| 55 | 55 | ||
| 56 | class VKFenceManager final : public GenericFenceManager { | 56 | class VKFenceManager final : public GenericFenceManager { |
| 57 | public: | 57 | public: |
| 58 | explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu, | 58 | explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, |
| 59 | Tegra::MemoryManager& memory_manager, VKTextureCache& texture_cache, | 59 | Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, |
| 60 | VKBufferCache& buffer_cache, VKQueryCache& query_cache, | 60 | VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, |
| 61 | const VKDevice& device, VKScheduler& scheduler); | 61 | const Device& device_, VKScheduler& scheduler_); |
| 62 | 62 | ||
| 63 | protected: | 63 | protected: |
| 64 | Fence CreateFence(u32 value, bool is_stubbed) override; | 64 | Fence CreateFence(u32 value, bool is_stubbed) override; |
| @@ -68,7 +68,7 @@ protected: | |||
| 68 | void WaitFence(Fence& fence) override; | 68 | void WaitFence(Fence& fence) override; |
| 69 | 69 | ||
| 70 | private: | 70 | private: |
| 71 | const VKDevice& device; | 71 | const Device& device; |
| 72 | VKScheduler& scheduler; | 72 | VKScheduler& scheduler; |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index a4b9e7ef5..a5214d0bc 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -12,13 +12,12 @@ | |||
| 12 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 12 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 13 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 13 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 14 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 14 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 15 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 16 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 15 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 17 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 16 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 18 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||
| 19 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 17 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 20 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 18 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 21 | #include "video_core/renderer_vulkan/wrapper.h" | 19 | #include "video_core/vulkan_common/vulkan_device.h" |
| 20 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 22 | 21 | ||
| 23 | namespace Vulkan { | 22 | namespace Vulkan { |
| 24 | 23 | ||
| @@ -69,23 +68,45 @@ VkViewportSwizzleNV UnpackViewportSwizzle(u16 swizzle) { | |||
| 69 | }; | 68 | }; |
| 70 | } | 69 | } |
| 71 | 70 | ||
| 71 | VkSampleCountFlagBits ConvertMsaaMode(Tegra::Texture::MsaaMode msaa_mode) { | ||
| 72 | switch (msaa_mode) { | ||
| 73 | case Tegra::Texture::MsaaMode::Msaa1x1: | ||
| 74 | return VK_SAMPLE_COUNT_1_BIT; | ||
| 75 | case Tegra::Texture::MsaaMode::Msaa2x1: | ||
| 76 | case Tegra::Texture::MsaaMode::Msaa2x1_D3D: | ||
| 77 | return VK_SAMPLE_COUNT_2_BIT; | ||
| 78 | case Tegra::Texture::MsaaMode::Msaa2x2: | ||
| 79 | case Tegra::Texture::MsaaMode::Msaa2x2_VC4: | ||
| 80 | case Tegra::Texture::MsaaMode::Msaa2x2_VC12: | ||
| 81 | return VK_SAMPLE_COUNT_4_BIT; | ||
| 82 | case Tegra::Texture::MsaaMode::Msaa4x2: | ||
| 83 | case Tegra::Texture::MsaaMode::Msaa4x2_D3D: | ||
| 84 | case Tegra::Texture::MsaaMode::Msaa4x2_VC8: | ||
| 85 | case Tegra::Texture::MsaaMode::Msaa4x2_VC24: | ||
| 86 | return VK_SAMPLE_COUNT_8_BIT; | ||
| 87 | case Tegra::Texture::MsaaMode::Msaa4x4: | ||
| 88 | return VK_SAMPLE_COUNT_16_BIT; | ||
| 89 | default: | ||
| 90 | UNREACHABLE_MSG("Invalid msaa_mode={}", static_cast<int>(msaa_mode)); | ||
| 91 | return VK_SAMPLE_COUNT_1_BIT; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 72 | } // Anonymous namespace | 95 | } // Anonymous namespace |
| 73 | 96 | ||
| 74 | VKGraphicsPipeline::VKGraphicsPipeline(const VKDevice& device, VKScheduler& scheduler, | 97 | VKGraphicsPipeline::VKGraphicsPipeline(const Device& device_, VKScheduler& scheduler_, |
| 75 | VKDescriptorPool& descriptor_pool, | 98 | VKDescriptorPool& descriptor_pool_, |
| 76 | VKUpdateDescriptorQueue& update_descriptor_queue, | 99 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 77 | VKRenderPassCache& renderpass_cache, | ||
| 78 | const GraphicsPipelineCacheKey& key, | 100 | const GraphicsPipelineCacheKey& key, |
| 79 | vk::Span<VkDescriptorSetLayoutBinding> bindings, | 101 | vk::Span<VkDescriptorSetLayoutBinding> bindings, |
| 80 | const SPIRVProgram& program) | 102 | const SPIRVProgram& program, u32 num_color_buffers) |
| 81 | : device{device}, scheduler{scheduler}, cache_key{key}, hash{cache_key.Hash()}, | 103 | : device{device_}, scheduler{scheduler_}, cache_key{key}, hash{cache_key.Hash()}, |
| 82 | descriptor_set_layout{CreateDescriptorSetLayout(bindings)}, | 104 | descriptor_set_layout{CreateDescriptorSetLayout(bindings)}, |
| 83 | descriptor_allocator{descriptor_pool, *descriptor_set_layout}, | 105 | descriptor_allocator{descriptor_pool_, *descriptor_set_layout}, |
| 84 | update_descriptor_queue{update_descriptor_queue}, layout{CreatePipelineLayout()}, | 106 | update_descriptor_queue{update_descriptor_queue_}, layout{CreatePipelineLayout()}, |
| 85 | descriptor_template{CreateDescriptorUpdateTemplate(program)}, modules{CreateShaderModules( | 107 | descriptor_template{CreateDescriptorUpdateTemplate(program)}, |
| 86 | program)}, | 108 | modules(CreateShaderModules(program)), |
| 87 | renderpass{renderpass_cache.GetRenderPass(cache_key.renderpass_params)}, | 109 | pipeline(CreatePipeline(program, cache_key.renderpass, num_color_buffers)) {} |
| 88 | pipeline{CreatePipeline(cache_key.renderpass_params, program)} {} | ||
| 89 | 110 | ||
| 90 | VKGraphicsPipeline::~VKGraphicsPipeline() = default; | 111 | VKGraphicsPipeline::~VKGraphicsPipeline() = default; |
| 91 | 112 | ||
| @@ -159,10 +180,11 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( | |||
| 159 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | 180 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, |
| 160 | .pNext = nullptr, | 181 | .pNext = nullptr, |
| 161 | .flags = 0, | 182 | .flags = 0, |
| 183 | .codeSize = 0, | ||
| 162 | }; | 184 | }; |
| 163 | 185 | ||
| 164 | std::vector<vk::ShaderModule> modules; | 186 | std::vector<vk::ShaderModule> shader_modules; |
| 165 | modules.reserve(Maxwell::MaxShaderStage); | 187 | shader_modules.reserve(Maxwell::MaxShaderStage); |
| 166 | for (std::size_t i = 0; i < Maxwell::MaxShaderStage; ++i) { | 188 | for (std::size_t i = 0; i < Maxwell::MaxShaderStage; ++i) { |
| 167 | const auto& stage = program[i]; | 189 | const auto& stage = program[i]; |
| 168 | if (!stage) { | 190 | if (!stage) { |
| @@ -173,13 +195,14 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( | |||
| 173 | 195 | ||
| 174 | ci.codeSize = stage->code.size() * sizeof(u32); | 196 | ci.codeSize = stage->code.size() * sizeof(u32); |
| 175 | ci.pCode = stage->code.data(); | 197 | ci.pCode = stage->code.data(); |
| 176 | modules.push_back(device.GetLogical().CreateShaderModule(ci)); | 198 | shader_modules.push_back(device.GetLogical().CreateShaderModule(ci)); |
| 177 | } | 199 | } |
| 178 | return modules; | 200 | return shader_modules; |
| 179 | } | 201 | } |
| 180 | 202 | ||
| 181 | vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, | 203 | vk::Pipeline VKGraphicsPipeline::CreatePipeline(const SPIRVProgram& program, |
| 182 | const SPIRVProgram& program) const { | 204 | VkRenderPass renderpass, |
| 205 | u32 num_color_buffers) const { | ||
| 183 | const auto& state = cache_key.fixed_state; | 206 | const auto& state = cache_key.fixed_state; |
| 184 | const auto& viewport_swizzles = state.viewport_swizzles; | 207 | const auto& viewport_swizzles = state.viewport_swizzles; |
| 185 | 208 | ||
| @@ -189,11 +212,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 189 | // state is ignored | 212 | // state is ignored |
| 190 | dynamic.raw1 = 0; | 213 | dynamic.raw1 = 0; |
| 191 | dynamic.raw2 = 0; | 214 | dynamic.raw2 = 0; |
| 192 | for (FixedPipelineState::VertexBinding& binding : dynamic.vertex_bindings) { | 215 | dynamic.vertex_strides.fill(0); |
| 193 | // Enable all vertex bindings | ||
| 194 | binding.raw = 0; | ||
| 195 | binding.enabled.Assign(1); | ||
| 196 | } | ||
| 197 | } else { | 216 | } else { |
| 198 | dynamic = state.dynamic_state; | 217 | dynamic = state.dynamic_state; |
| 199 | } | 218 | } |
| @@ -201,19 +220,16 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 201 | std::vector<VkVertexInputBindingDescription> vertex_bindings; | 220 | std::vector<VkVertexInputBindingDescription> vertex_bindings; |
| 202 | std::vector<VkVertexInputBindingDivisorDescriptionEXT> vertex_binding_divisors; | 221 | std::vector<VkVertexInputBindingDivisorDescriptionEXT> vertex_binding_divisors; |
| 203 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 222 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 204 | const auto& binding = dynamic.vertex_bindings[index]; | 223 | if (state.attributes[index].binding_index_enabled == 0) { |
| 205 | if (!binding.enabled) { | ||
| 206 | continue; | 224 | continue; |
| 207 | } | 225 | } |
| 208 | const bool instanced = state.binding_divisors[index] != 0; | 226 | const bool instanced = state.binding_divisors[index] != 0; |
| 209 | const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; | 227 | const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; |
| 210 | |||
| 211 | vertex_bindings.push_back({ | 228 | vertex_bindings.push_back({ |
| 212 | .binding = static_cast<u32>(index), | 229 | .binding = static_cast<u32>(index), |
| 213 | .stride = binding.stride, | 230 | .stride = dynamic.vertex_strides[index], |
| 214 | .inputRate = rate, | 231 | .inputRate = rate, |
| 215 | }); | 232 | }); |
| 216 | |||
| 217 | if (instanced) { | 233 | if (instanced) { |
| 218 | vertex_binding_divisors.push_back({ | 234 | vertex_binding_divisors.push_back({ |
| 219 | .binding = static_cast<u32>(index), | 235 | .binding = static_cast<u32>(index), |
| @@ -229,7 +245,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 229 | if (!attribute.enabled) { | 245 | if (!attribute.enabled) { |
| 230 | continue; | 246 | continue; |
| 231 | } | 247 | } |
| 232 | if (input_attributes.find(static_cast<u32>(index)) == input_attributes.end()) { | 248 | if (!input_attributes.contains(static_cast<u32>(index))) { |
| 233 | // Skip attributes not used by the vertex shaders. | 249 | // Skip attributes not used by the vertex shaders. |
| 234 | continue; | 250 | continue; |
| 235 | } | 251 | } |
| @@ -261,12 +277,12 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 261 | vertex_input_ci.pNext = &input_divisor_ci; | 277 | vertex_input_ci.pNext = &input_divisor_ci; |
| 262 | } | 278 | } |
| 263 | 279 | ||
| 264 | const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); | 280 | const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, state.topology); |
| 265 | const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ | 281 | const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ |
| 266 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | 282 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, |
| 267 | .pNext = nullptr, | 283 | .pNext = nullptr, |
| 268 | .flags = 0, | 284 | .flags = 0, |
| 269 | .topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()), | 285 | .topology = MaxwellToVK::PrimitiveTopology(device, state.topology), |
| 270 | .primitiveRestartEnable = state.primitive_restart_enable != 0 && | 286 | .primitiveRestartEnable = state.primitive_restart_enable != 0 && |
| 271 | SupportsPrimitiveRestart(input_assembly_topology), | 287 | SupportsPrimitiveRestart(input_assembly_topology), |
| 272 | }; | 288 | }; |
| @@ -289,8 +305,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 289 | }; | 305 | }; |
| 290 | 306 | ||
| 291 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; | 307 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; |
| 292 | std::transform(viewport_swizzles.begin(), viewport_swizzles.end(), swizzles.begin(), | 308 | std::ranges::transform(viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); |
| 293 | UnpackViewportSwizzle); | ||
| 294 | VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ | 309 | VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ |
| 295 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, | 310 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, |
| 296 | .pNext = nullptr, | 311 | .pNext = nullptr, |
| @@ -325,7 +340,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 325 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | 340 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| 326 | .pNext = nullptr, | 341 | .pNext = nullptr, |
| 327 | .flags = 0, | 342 | .flags = 0, |
| 328 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | 343 | .rasterizationSamples = ConvertMsaaMode(state.msaa_mode), |
| 329 | .sampleShadingEnable = VK_FALSE, | 344 | .sampleShadingEnable = VK_FALSE, |
| 330 | .minSampleShading = 0.0f, | 345 | .minSampleShading = 0.0f, |
| 331 | .pSampleMask = nullptr, | 346 | .pSampleMask = nullptr, |
| @@ -351,8 +366,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 351 | }; | 366 | }; |
| 352 | 367 | ||
| 353 | std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; | 368 | std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; |
| 354 | const auto num_attachments = static_cast<std::size_t>(renderpass_params.num_color_attachments); | 369 | for (std::size_t index = 0; index < num_color_buffers; ++index) { |
| 355 | for (std::size_t index = 0; index < num_attachments; ++index) { | ||
| 356 | static constexpr std::array COMPONENT_TABLE{ | 370 | static constexpr std::array COMPONENT_TABLE{ |
| 357 | VK_COLOR_COMPONENT_R_BIT, | 371 | VK_COLOR_COMPONENT_R_BIT, |
| 358 | VK_COLOR_COMPONENT_G_BIT, | 372 | VK_COLOR_COMPONENT_G_BIT, |
| @@ -386,8 +400,9 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 386 | .flags = 0, | 400 | .flags = 0, |
| 387 | .logicOpEnable = VK_FALSE, | 401 | .logicOpEnable = VK_FALSE, |
| 388 | .logicOp = VK_LOGIC_OP_COPY, | 402 | .logicOp = VK_LOGIC_OP_COPY, |
| 389 | .attachmentCount = static_cast<u32>(num_attachments), | 403 | .attachmentCount = num_color_buffers, |
| 390 | .pAttachments = cb_attachments.data(), | 404 | .pAttachments = cb_attachments.data(), |
| 405 | .blendConstants = {}, | ||
| 391 | }; | 406 | }; |
| 392 | 407 | ||
| 393 | std::vector dynamic_states{ | 408 | std::vector dynamic_states{ |
| @@ -400,7 +415,6 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 400 | static constexpr std::array extended{ | 415 | static constexpr std::array extended{ |
| 401 | VK_DYNAMIC_STATE_CULL_MODE_EXT, | 416 | VK_DYNAMIC_STATE_CULL_MODE_EXT, |
| 402 | VK_DYNAMIC_STATE_FRONT_FACE_EXT, | 417 | VK_DYNAMIC_STATE_FRONT_FACE_EXT, |
| 403 | VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT, | ||
| 404 | VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, | 418 | VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, |
| 405 | VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, | 419 | VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, |
| 406 | VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, | 420 | VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, |
| @@ -446,8 +460,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 446 | stage_ci.pNext = &subgroup_size_ci; | 460 | stage_ci.pNext = &subgroup_size_ci; |
| 447 | } | 461 | } |
| 448 | } | 462 | } |
| 449 | 463 | return device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ | |
| 450 | const VkGraphicsPipelineCreateInfo ci{ | ||
| 451 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | 464 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, |
| 452 | .pNext = nullptr, | 465 | .pNext = nullptr, |
| 453 | .flags = 0, | 466 | .flags = 0, |
| @@ -467,8 +480,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 467 | .subpass = 0, | 480 | .subpass = 0, |
| 468 | .basePipelineHandle = nullptr, | 481 | .basePipelineHandle = nullptr, |
| 469 | .basePipelineIndex = 0, | 482 | .basePipelineIndex = 0, |
| 470 | }; | 483 | }); |
| 471 | return device.GetLogical().CreateGraphicsPipeline(ci); | ||
| 472 | } | 484 | } |
| 473 | 485 | ||
| 474 | } // namespace Vulkan | 486 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 58aa35efd..8b6a98fe0 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h | |||
| @@ -8,20 +8,19 @@ | |||
| 8 | #include <optional> | 8 | #include <optional> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | ||
| 11 | #include "video_core/engines/maxwell_3d.h" | 12 | #include "video_core/engines/maxwell_3d.h" |
| 12 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 13 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 13 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 14 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 14 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | 15 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" |
| 16 | #include "video_core/renderer_vulkan/wrapper.h" | 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 17 | 17 | ||
| 18 | namespace Vulkan { | 18 | namespace Vulkan { |
| 19 | 19 | ||
| 20 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 20 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 21 | 21 | ||
| 22 | struct GraphicsPipelineCacheKey { | 22 | struct GraphicsPipelineCacheKey { |
| 23 | RenderPassParams renderpass_params; | 23 | VkRenderPass renderpass; |
| 24 | u32 padding; | ||
| 25 | std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders; | 24 | std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders; |
| 26 | FixedPipelineState fixed_state; | 25 | FixedPipelineState fixed_state; |
| 27 | 26 | ||
| @@ -34,16 +33,15 @@ struct GraphicsPipelineCacheKey { | |||
| 34 | } | 33 | } |
| 35 | 34 | ||
| 36 | std::size_t Size() const noexcept { | 35 | std::size_t Size() const noexcept { |
| 37 | return sizeof(renderpass_params) + sizeof(padding) + sizeof(shaders) + fixed_state.Size(); | 36 | return sizeof(renderpass) + sizeof(shaders) + fixed_state.Size(); |
| 38 | } | 37 | } |
| 39 | }; | 38 | }; |
| 40 | static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>); | 39 | static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>); |
| 41 | static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>); | 40 | static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>); |
| 42 | static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>); | 41 | static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>); |
| 43 | 42 | ||
| 43 | class Device; | ||
| 44 | class VKDescriptorPool; | 44 | class VKDescriptorPool; |
| 45 | class VKDevice; | ||
| 46 | class VKRenderPassCache; | ||
| 47 | class VKScheduler; | 45 | class VKScheduler; |
| 48 | class VKUpdateDescriptorQueue; | 46 | class VKUpdateDescriptorQueue; |
| 49 | 47 | ||
| @@ -51,13 +49,12 @@ using SPIRVProgram = std::array<std::optional<SPIRVShader>, Maxwell::MaxShaderSt | |||
| 51 | 49 | ||
| 52 | class VKGraphicsPipeline final { | 50 | class VKGraphicsPipeline final { |
| 53 | public: | 51 | public: |
| 54 | explicit VKGraphicsPipeline(const VKDevice& device, VKScheduler& scheduler, | 52 | explicit VKGraphicsPipeline(const Device& device_, VKScheduler& scheduler_, |
| 55 | VKDescriptorPool& descriptor_pool, | 53 | VKDescriptorPool& descriptor_pool, |
| 56 | VKUpdateDescriptorQueue& update_descriptor_queue, | 54 | VKUpdateDescriptorQueue& update_descriptor_queue_, |
| 57 | VKRenderPassCache& renderpass_cache, | ||
| 58 | const GraphicsPipelineCacheKey& key, | 55 | const GraphicsPipelineCacheKey& key, |
| 59 | vk::Span<VkDescriptorSetLayoutBinding> bindings, | 56 | vk::Span<VkDescriptorSetLayoutBinding> bindings, |
| 60 | const SPIRVProgram& program); | 57 | const SPIRVProgram& program, u32 num_color_buffers); |
| 61 | ~VKGraphicsPipeline(); | 58 | ~VKGraphicsPipeline(); |
| 62 | 59 | ||
| 63 | VkDescriptorSet CommitDescriptorSet(); | 60 | VkDescriptorSet CommitDescriptorSet(); |
| @@ -70,10 +67,6 @@ public: | |||
| 70 | return *layout; | 67 | return *layout; |
| 71 | } | 68 | } |
| 72 | 69 | ||
| 73 | VkRenderPass GetRenderPass() const { | ||
| 74 | return renderpass; | ||
| 75 | } | ||
| 76 | |||
| 77 | GraphicsPipelineCacheKey GetCacheKey() const { | 70 | GraphicsPipelineCacheKey GetCacheKey() const { |
| 78 | return cache_key; | 71 | return cache_key; |
| 79 | } | 72 | } |
| @@ -89,10 +82,10 @@ private: | |||
| 89 | 82 | ||
| 90 | std::vector<vk::ShaderModule> CreateShaderModules(const SPIRVProgram& program) const; | 83 | std::vector<vk::ShaderModule> CreateShaderModules(const SPIRVProgram& program) const; |
| 91 | 84 | ||
| 92 | vk::Pipeline CreatePipeline(const RenderPassParams& renderpass_params, | 85 | vk::Pipeline CreatePipeline(const SPIRVProgram& program, VkRenderPass renderpass, |
| 93 | const SPIRVProgram& program) const; | 86 | u32 num_color_buffers) const; |
| 94 | 87 | ||
| 95 | const VKDevice& device; | 88 | const Device& device; |
| 96 | VKScheduler& scheduler; | 89 | VKScheduler& scheduler; |
| 97 | const GraphicsPipelineCacheKey cache_key; | 90 | const GraphicsPipelineCacheKey cache_key; |
| 98 | const u64 hash; | 91 | const u64 hash; |
| @@ -104,7 +97,6 @@ private: | |||
| 104 | vk::DescriptorUpdateTemplateKHR descriptor_template; | 97 | vk::DescriptorUpdateTemplateKHR descriptor_template; |
| 105 | std::vector<vk::ShaderModule> modules; | 98 | std::vector<vk::ShaderModule> modules; |
| 106 | 99 | ||
| 107 | VkRenderPass renderpass; | ||
| 108 | vk::Pipeline pipeline; | 100 | vk::Pipeline pipeline; |
| 109 | }; | 101 | }; |
| 110 | 102 | ||
diff --git a/src/video_core/renderer_vulkan/vk_image.cpp b/src/video_core/renderer_vulkan/vk_image.cpp deleted file mode 100644 index 1c418ea17..000000000 --- a/src/video_core/renderer_vulkan/vk_image.cpp +++ /dev/null | |||
| @@ -1,135 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include <vector> | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_image.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 12 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | VKImage::VKImage(const VKDevice& device, VKScheduler& scheduler, const VkImageCreateInfo& image_ci, | ||
| 17 | VkImageAspectFlags aspect_mask) | ||
| 18 | : device{device}, scheduler{scheduler}, format{image_ci.format}, aspect_mask{aspect_mask}, | ||
| 19 | image_num_layers{image_ci.arrayLayers}, image_num_levels{image_ci.mipLevels} { | ||
| 20 | UNIMPLEMENTED_IF_MSG(image_ci.queueFamilyIndexCount != 0, | ||
| 21 | "Queue family tracking is not implemented"); | ||
| 22 | |||
| 23 | image = device.GetLogical().CreateImage(image_ci); | ||
| 24 | |||
| 25 | const u32 num_ranges = image_num_layers * image_num_levels; | ||
| 26 | barriers.resize(num_ranges); | ||
| 27 | subrange_states.resize(num_ranges, {{}, image_ci.initialLayout}); | ||
| 28 | } | ||
| 29 | |||
| 30 | VKImage::~VKImage() = default; | ||
| 31 | |||
| 32 | void VKImage::Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | ||
| 33 | VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access, | ||
| 34 | VkImageLayout new_layout) { | ||
| 35 | if (!HasChanged(base_layer, num_layers, base_level, num_levels, new_access, new_layout)) { | ||
| 36 | return; | ||
| 37 | } | ||
| 38 | |||
| 39 | std::size_t cursor = 0; | ||
| 40 | for (u32 layer_it = 0; layer_it < num_layers; ++layer_it) { | ||
| 41 | for (u32 level_it = 0; level_it < num_levels; ++level_it, ++cursor) { | ||
| 42 | const u32 layer = base_layer + layer_it; | ||
| 43 | const u32 level = base_level + level_it; | ||
| 44 | auto& state = GetSubrangeState(layer, level); | ||
| 45 | auto& barrier = barriers[cursor]; | ||
| 46 | barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; | ||
| 47 | barrier.pNext = nullptr; | ||
| 48 | barrier.srcAccessMask = state.access; | ||
| 49 | barrier.dstAccessMask = new_access; | ||
| 50 | barrier.oldLayout = state.layout; | ||
| 51 | barrier.newLayout = new_layout; | ||
| 52 | barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | ||
| 53 | barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | ||
| 54 | barrier.image = *image; | ||
| 55 | barrier.subresourceRange.aspectMask = aspect_mask; | ||
| 56 | barrier.subresourceRange.baseMipLevel = level; | ||
| 57 | barrier.subresourceRange.levelCount = 1; | ||
| 58 | barrier.subresourceRange.baseArrayLayer = layer; | ||
| 59 | barrier.subresourceRange.layerCount = 1; | ||
| 60 | state.access = new_access; | ||
| 61 | state.layout = new_layout; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 66 | |||
| 67 | scheduler.Record([barriers = barriers, cursor](vk::CommandBuffer cmdbuf) { | ||
| 68 | // TODO(Rodrigo): Implement a way to use the latest stage across subresources. | ||
| 69 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 70 | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, {}, {}, | ||
| 71 | vk::Span(barriers.data(), cursor)); | ||
| 72 | }); | ||
| 73 | } | ||
| 74 | |||
| 75 | bool VKImage::HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | ||
| 76 | VkAccessFlags new_access, VkImageLayout new_layout) noexcept { | ||
| 77 | const bool is_full_range = base_layer == 0 && num_layers == image_num_layers && | ||
| 78 | base_level == 0 && num_levels == image_num_levels; | ||
| 79 | if (!is_full_range) { | ||
| 80 | state_diverged = true; | ||
| 81 | } | ||
| 82 | |||
| 83 | if (!state_diverged) { | ||
| 84 | auto& state = GetSubrangeState(0, 0); | ||
| 85 | if (state.access != new_access || state.layout != new_layout) { | ||
| 86 | return true; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | for (u32 layer_it = 0; layer_it < num_layers; ++layer_it) { | ||
| 91 | for (u32 level_it = 0; level_it < num_levels; ++level_it) { | ||
| 92 | const u32 layer = base_layer + layer_it; | ||
| 93 | const u32 level = base_level + level_it; | ||
| 94 | auto& state = GetSubrangeState(layer, level); | ||
| 95 | if (state.access != new_access || state.layout != new_layout) { | ||
| 96 | return true; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | return false; | ||
| 101 | } | ||
| 102 | |||
| 103 | void VKImage::CreatePresentView() { | ||
| 104 | // Image type has to be 2D to be presented. | ||
| 105 | present_view = device.GetLogical().CreateImageView({ | ||
| 106 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 107 | .pNext = nullptr, | ||
| 108 | .flags = 0, | ||
| 109 | .image = *image, | ||
| 110 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 111 | .format = format, | ||
| 112 | .components = | ||
| 113 | { | ||
| 114 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 115 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 116 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 117 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 118 | }, | ||
| 119 | .subresourceRange = | ||
| 120 | { | ||
| 121 | .aspectMask = aspect_mask, | ||
| 122 | .baseMipLevel = 0, | ||
| 123 | .levelCount = 1, | ||
| 124 | .baseArrayLayer = 0, | ||
| 125 | .layerCount = 1, | ||
| 126 | }, | ||
| 127 | }); | ||
| 128 | } | ||
| 129 | |||
| 130 | VKImage::SubrangeState& VKImage::GetSubrangeState(u32 layer, u32 level) noexcept { | ||
| 131 | return subrange_states[static_cast<std::size_t>(layer * image_num_levels) + | ||
| 132 | static_cast<std::size_t>(level)]; | ||
| 133 | } | ||
| 134 | |||
| 135 | } // namespace Vulkan \ No newline at end of file | ||
diff --git a/src/video_core/renderer_vulkan/vk_image.h b/src/video_core/renderer_vulkan/vk_image.h deleted file mode 100644 index b4d7229e5..000000000 --- a/src/video_core/renderer_vulkan/vk_image.h +++ /dev/null | |||
| @@ -1,84 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | class VKDevice; | ||
| 16 | class VKScheduler; | ||
| 17 | |||
| 18 | class VKImage { | ||
| 19 | public: | ||
| 20 | explicit VKImage(const VKDevice& device, VKScheduler& scheduler, | ||
| 21 | const VkImageCreateInfo& image_ci, VkImageAspectFlags aspect_mask); | ||
| 22 | ~VKImage(); | ||
| 23 | |||
| 24 | /// Records in the passed command buffer an image transition and updates the state of the image. | ||
| 25 | void Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | ||
| 26 | VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access, | ||
| 27 | VkImageLayout new_layout); | ||
| 28 | |||
| 29 | /// Returns a view compatible with presentation, the image has to be 2D. | ||
| 30 | VkImageView GetPresentView() { | ||
| 31 | if (!present_view) { | ||
| 32 | CreatePresentView(); | ||
| 33 | } | ||
| 34 | return *present_view; | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Returns the Vulkan image handler. | ||
| 38 | const vk::Image& GetHandle() const { | ||
| 39 | return image; | ||
| 40 | } | ||
| 41 | |||
| 42 | /// Returns the Vulkan format for this image. | ||
| 43 | VkFormat GetFormat() const { | ||
| 44 | return format; | ||
| 45 | } | ||
| 46 | |||
| 47 | /// Returns the Vulkan aspect mask. | ||
| 48 | VkImageAspectFlags GetAspectMask() const { | ||
| 49 | return aspect_mask; | ||
| 50 | } | ||
| 51 | |||
| 52 | private: | ||
| 53 | struct SubrangeState final { | ||
| 54 | VkAccessFlags access = 0; ///< Current access bits. | ||
| 55 | VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; ///< Current image layout. | ||
| 56 | }; | ||
| 57 | |||
| 58 | bool HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | ||
| 59 | VkAccessFlags new_access, VkImageLayout new_layout) noexcept; | ||
| 60 | |||
| 61 | /// Creates a presentation view. | ||
| 62 | void CreatePresentView(); | ||
| 63 | |||
| 64 | /// Returns the subrange state for a layer and layer. | ||
| 65 | SubrangeState& GetSubrangeState(u32 layer, u32 level) noexcept; | ||
| 66 | |||
| 67 | const VKDevice& device; ///< Device handler. | ||
| 68 | VKScheduler& scheduler; ///< Device scheduler. | ||
| 69 | |||
| 70 | const VkFormat format; ///< Vulkan format. | ||
| 71 | const VkImageAspectFlags aspect_mask; ///< Vulkan aspect mask. | ||
| 72 | const u32 image_num_layers; ///< Number of layers. | ||
| 73 | const u32 image_num_levels; ///< Number of mipmap levels. | ||
| 74 | |||
| 75 | vk::Image image; ///< Image handle. | ||
| 76 | vk::ImageView present_view; ///< Image view compatible with presentation. | ||
| 77 | |||
| 78 | std::vector<VkImageMemoryBarrier> barriers; ///< Pool of barriers. | ||
| 79 | std::vector<SubrangeState> subrange_states; ///< Current subrange state. | ||
| 80 | |||
| 81 | bool state_diverged = false; ///< True when subresources mismatch in layout. | ||
| 82 | }; | ||
| 83 | |||
| 84 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index ae26e558d..56ec5e380 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp | |||
| @@ -6,15 +6,15 @@ | |||
| 6 | #include <chrono> | 6 | #include <chrono> |
| 7 | 7 | ||
| 8 | #include "core/settings.h" | 8 | #include "core/settings.h" |
| 9 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 9 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_device.h" |
| 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 12 | 12 | ||
| 13 | namespace Vulkan { | 13 | namespace Vulkan { |
| 14 | 14 | ||
| 15 | using namespace std::chrono_literals; | 15 | using namespace std::chrono_literals; |
| 16 | 16 | ||
| 17 | MasterSemaphore::MasterSemaphore(const VKDevice& device) { | 17 | MasterSemaphore::MasterSemaphore(const Device& device) { |
| 18 | static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{ | 18 | static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{ |
| 19 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR, | 19 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR, |
| 20 | .pNext = nullptr, | 20 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 0e93706d7..f336f1862 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h | |||
| @@ -8,15 +8,15 @@ | |||
| 8 | #include <thread> | 8 | #include <thread> |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 12 | 12 | ||
| 13 | namespace Vulkan { | 13 | namespace Vulkan { |
| 14 | 14 | ||
| 15 | class VKDevice; | 15 | class Device; |
| 16 | 16 | ||
| 17 | class MasterSemaphore { | 17 | class MasterSemaphore { |
| 18 | public: | 18 | public: |
| 19 | explicit MasterSemaphore(const VKDevice& device); | 19 | explicit MasterSemaphore(const Device& device); |
| 20 | ~MasterSemaphore(); | 20 | ~MasterSemaphore(); |
| 21 | 21 | ||
| 22 | /// Returns the current logical tick. | 22 | /// Returns the current logical tick. |
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp index 24c8960ac..a6abd0eee 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp | |||
| @@ -11,9 +11,9 @@ | |||
| 11 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| 14 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 14 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 16 | #include "video_core/renderer_vulkan/wrapper.h" | 15 | #include "video_core/vulkan_common/vulkan_device.h" |
| 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 17 | 17 | ||
| 18 | namespace Vulkan { | 18 | namespace Vulkan { |
| 19 | 19 | ||
| @@ -29,10 +29,10 @@ u64 GetAllocationChunkSize(u64 required_size) { | |||
| 29 | 29 | ||
| 30 | class VKMemoryAllocation final { | 30 | class VKMemoryAllocation final { |
| 31 | public: | 31 | public: |
| 32 | explicit VKMemoryAllocation(const VKDevice& device, vk::DeviceMemory memory, | 32 | explicit VKMemoryAllocation(const Device& device_, vk::DeviceMemory memory_, |
| 33 | VkMemoryPropertyFlags properties, u64 allocation_size, u32 type) | 33 | VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) |
| 34 | : device{device}, memory{std::move(memory)}, properties{properties}, | 34 | : device{device_}, memory{std::move(memory_)}, properties{properties_}, |
| 35 | allocation_size{allocation_size}, shifted_type{ShiftType(type)} {} | 35 | allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {} |
| 36 | 36 | ||
| 37 | VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) { | 37 | VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) { |
| 38 | auto found = TryFindFreeSection(free_iterator, allocation_size, | 38 | auto found = TryFindFreeSection(free_iterator, allocation_size, |
| @@ -104,7 +104,7 @@ private: | |||
| 104 | return std::nullopt; | 104 | return std::nullopt; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | const VKDevice& device; ///< Vulkan device. | 107 | const Device& device; ///< Vulkan device. |
| 108 | const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. | 108 | const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. |
| 109 | const VkMemoryPropertyFlags properties; ///< Vulkan properties. | 109 | const VkMemoryPropertyFlags properties; ///< Vulkan properties. |
| 110 | const u64 allocation_size; ///< Size of this allocation. | 110 | const u64 allocation_size; ///< Size of this allocation. |
| @@ -117,8 +117,8 @@ private: | |||
| 117 | std::vector<const VKMemoryCommitImpl*> commits; | 117 | std::vector<const VKMemoryCommitImpl*> commits; |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | VKMemoryManager::VKMemoryManager(const VKDevice& device) | 120 | VKMemoryManager::VKMemoryManager(const Device& device_) |
| 121 | : device{device}, properties{device.GetPhysical().GetMemoryProperties()} {} | 121 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} |
| 122 | 122 | ||
| 123 | VKMemoryManager::~VKMemoryManager() = default; | 123 | VKMemoryManager::~VKMemoryManager() = default; |
| 124 | 124 | ||
| @@ -207,16 +207,16 @@ VKMemoryCommit VKMemoryManager::TryAllocCommit(const VkMemoryRequirements& requi | |||
| 207 | return {}; | 207 | return {}; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | VKMemoryCommitImpl::VKMemoryCommitImpl(const VKDevice& device, VKMemoryAllocation* allocation, | 210 | VKMemoryCommitImpl::VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, |
| 211 | const vk::DeviceMemory& memory, u64 begin, u64 end) | 211 | const vk::DeviceMemory& memory_, u64 begin_, u64 end_) |
| 212 | : device{device}, memory{memory}, interval{begin, end}, allocation{allocation} {} | 212 | : device{device_}, memory{memory_}, interval{begin_, end_}, allocation{allocation_} {} |
| 213 | 213 | ||
| 214 | VKMemoryCommitImpl::~VKMemoryCommitImpl() { | 214 | VKMemoryCommitImpl::~VKMemoryCommitImpl() { |
| 215 | allocation->Free(this); | 215 | allocation->Free(this); |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const { | 218 | MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const { |
| 219 | return MemoryMap{this, memory.Map(interval.first + offset_, size)}; | 219 | return MemoryMap(this, std::span<u8>(memory.Map(interval.first + offset_, size), size)); |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | void VKMemoryCommitImpl::Unmap() const { | 222 | void VKMemoryCommitImpl::Unmap() const { |
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h index 1af88e3d4..2452bca4e 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ b/src/video_core/renderer_vulkan/vk_memory_manager.h | |||
| @@ -5,15 +5,16 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <span> | ||
| 8 | #include <utility> | 9 | #include <utility> |
| 9 | #include <vector> | 10 | #include <vector> |
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 12 | 13 | ||
| 13 | namespace Vulkan { | 14 | namespace Vulkan { |
| 14 | 15 | ||
| 16 | class Device; | ||
| 15 | class MemoryMap; | 17 | class MemoryMap; |
| 16 | class VKDevice; | ||
| 17 | class VKMemoryAllocation; | 18 | class VKMemoryAllocation; |
| 18 | class VKMemoryCommitImpl; | 19 | class VKMemoryCommitImpl; |
| 19 | 20 | ||
| @@ -21,7 +22,7 @@ using VKMemoryCommit = std::unique_ptr<VKMemoryCommitImpl>; | |||
| 21 | 22 | ||
| 22 | class VKMemoryManager final { | 23 | class VKMemoryManager final { |
| 23 | public: | 24 | public: |
| 24 | explicit VKMemoryManager(const VKDevice& device); | 25 | explicit VKMemoryManager(const Device& device_); |
| 25 | VKMemoryManager(const VKMemoryManager&) = delete; | 26 | VKMemoryManager(const VKMemoryManager&) = delete; |
| 26 | ~VKMemoryManager(); | 27 | ~VKMemoryManager(); |
| 27 | 28 | ||
| @@ -48,7 +49,7 @@ private: | |||
| 48 | VKMemoryCommit TryAllocCommit(const VkMemoryRequirements& requirements, | 49 | VKMemoryCommit TryAllocCommit(const VkMemoryRequirements& requirements, |
| 49 | VkMemoryPropertyFlags wanted_properties); | 50 | VkMemoryPropertyFlags wanted_properties); |
| 50 | 51 | ||
| 51 | const VKDevice& device; ///< Device handler. | 52 | const Device& device; ///< Device handler. |
| 52 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | 53 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. |
| 53 | std::vector<std::unique_ptr<VKMemoryAllocation>> allocations; ///< Current allocations. | 54 | std::vector<std::unique_ptr<VKMemoryAllocation>> allocations; ///< Current allocations. |
| 54 | }; | 55 | }; |
| @@ -58,8 +59,8 @@ class VKMemoryCommitImpl final { | |||
| 58 | friend MemoryMap; | 59 | friend MemoryMap; |
| 59 | 60 | ||
| 60 | public: | 61 | public: |
| 61 | explicit VKMemoryCommitImpl(const VKDevice& device, VKMemoryAllocation* allocation, | 62 | explicit VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, |
| 62 | const vk::DeviceMemory& memory, u64 begin, u64 end); | 63 | const vk::DeviceMemory& memory_, u64 begin_, u64 end_); |
| 63 | ~VKMemoryCommitImpl(); | 64 | ~VKMemoryCommitImpl(); |
| 64 | 65 | ||
| 65 | /// Maps a memory region and returns a pointer to it. | 66 | /// Maps a memory region and returns a pointer to it. |
| @@ -84,7 +85,7 @@ private: | |||
| 84 | /// Unmaps memory. | 85 | /// Unmaps memory. |
| 85 | void Unmap() const; | 86 | void Unmap() const; |
| 86 | 87 | ||
| 87 | const VKDevice& device; ///< Vulkan device. | 88 | const Device& device; ///< Vulkan device. |
| 88 | const vk::DeviceMemory& memory; ///< Vulkan device memory handler. | 89 | const vk::DeviceMemory& memory; ///< Vulkan device memory handler. |
| 89 | std::pair<u64, u64> interval{}; ///< Interval where the commit exists. | 90 | std::pair<u64, u64> interval{}; ///< Interval where the commit exists. |
| 90 | VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. | 91 | VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. |
| @@ -93,8 +94,8 @@ private: | |||
| 93 | /// Holds ownership of a memory map. | 94 | /// Holds ownership of a memory map. |
| 94 | class MemoryMap final { | 95 | class MemoryMap final { |
| 95 | public: | 96 | public: |
| 96 | explicit MemoryMap(const VKMemoryCommitImpl* commit, u8* address) | 97 | explicit MemoryMap(const VKMemoryCommitImpl* commit_, std::span<u8> span_) |
| 97 | : commit{commit}, address{address} {} | 98 | : commit{commit_}, span{span_} {} |
| 98 | 99 | ||
| 99 | ~MemoryMap() { | 100 | ~MemoryMap() { |
| 100 | if (commit) { | 101 | if (commit) { |
| @@ -108,19 +109,24 @@ public: | |||
| 108 | commit = nullptr; | 109 | commit = nullptr; |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 112 | /// Returns a span to the memory map. | ||
| 113 | [[nodiscard]] std::span<u8> Span() const noexcept { | ||
| 114 | return span; | ||
| 115 | } | ||
| 116 | |||
| 111 | /// Returns the address of the memory map. | 117 | /// Returns the address of the memory map. |
| 112 | u8* GetAddress() const { | 118 | [[nodiscard]] u8* Address() const noexcept { |
| 113 | return address; | 119 | return span.data(); |
| 114 | } | 120 | } |
| 115 | 121 | ||
| 116 | /// Returns the address of the memory map; | 122 | /// Returns the address of the memory map; |
| 117 | operator u8*() const { | 123 | [[nodiscard]] operator u8*() const noexcept { |
| 118 | return address; | 124 | return span.data(); |
| 119 | } | 125 | } |
| 120 | 126 | ||
| 121 | private: | 127 | private: |
| 122 | const VKMemoryCommitImpl* commit{}; ///< Mapped memory commit. | 128 | const VKMemoryCommitImpl* commit{}; ///< Mapped memory commit. |
| 123 | u8* address{}; ///< Address to the mapped memory. | 129 | std::span<u8> span; ///< Address to the mapped memory. |
| 124 | }; | 130 | }; |
| 125 | 131 | ||
| 126 | } // namespace Vulkan | 132 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 5c038f4bc..02282e36f 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "common/bit_cast.h" | ||
| 11 | #include "common/cityhash.h" | ||
| 10 | #include "common/microprofile.h" | 12 | #include "common/microprofile.h" |
| 11 | #include "core/core.h" | 13 | #include "core/core.h" |
| 12 | #include "core/memory.h" | 14 | #include "core/memory.h" |
| @@ -17,18 +19,17 @@ | |||
| 17 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 19 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 18 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" | 20 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" |
| 19 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 21 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 20 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 21 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 22 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 22 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 23 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 23 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 24 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 24 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||
| 25 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 25 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 26 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 26 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 27 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 28 | #include "video_core/shader/compiler_settings.h" | 27 | #include "video_core/shader/compiler_settings.h" |
| 29 | #include "video_core/shader/memory_util.h" | 28 | #include "video_core/shader/memory_util.h" |
| 30 | #include "video_core/shader_cache.h" | 29 | #include "video_core/shader_cache.h" |
| 31 | #include "video_core/shader_notify.h" | 30 | #include "video_core/shader_notify.h" |
| 31 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 32 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 32 | 33 | ||
| 33 | namespace Vulkan { | 34 | namespace Vulkan { |
| 34 | 35 | ||
| @@ -51,7 +52,9 @@ constexpr VkDescriptorType STORAGE_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_TEX | |||
| 51 | constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; | 52 | constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; |
| 52 | 53 | ||
| 53 | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ | 54 | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ |
| 54 | VideoCommon::Shader::CompileDepth::FullDecompile}; | 55 | .depth = VideoCommon::Shader::CompileDepth::FullDecompile, |
| 56 | .disable_else_derivation = true, | ||
| 57 | }; | ||
| 55 | 58 | ||
| 56 | constexpr std::size_t GetStageFromProgram(std::size_t program) { | 59 | constexpr std::size_t GetStageFromProgram(std::size_t program) { |
| 57 | return program == 0 ? 0 : program - 1; | 60 | return program == 0 ? 0 : program - 1; |
| @@ -74,7 +77,7 @@ ShaderType GetShaderType(Maxwell::ShaderProgram program) { | |||
| 74 | case Maxwell::ShaderProgram::Fragment: | 77 | case Maxwell::ShaderProgram::Fragment: |
| 75 | return ShaderType::Fragment; | 78 | return ShaderType::Fragment; |
| 76 | default: | 79 | default: |
| 77 | UNIMPLEMENTED_MSG("program={}", static_cast<u32>(program)); | 80 | UNIMPLEMENTED_MSG("program={}", program); |
| 78 | return ShaderType::Vertex; | 81 | return ShaderType::Vertex; |
| 79 | } | 82 | } |
| 80 | } | 83 | } |
| @@ -135,26 +138,24 @@ bool ComputePipelineCacheKey::operator==(const ComputePipelineCacheKey& rhs) con | |||
| 135 | return std::memcmp(&rhs, this, sizeof *this) == 0; | 138 | return std::memcmp(&rhs, this, sizeof *this) == 0; |
| 136 | } | 139 | } |
| 137 | 140 | ||
| 138 | Shader::Shader(Tegra::Engines::ConstBufferEngineInterface& engine, Tegra::Engines::ShaderType stage, | 141 | Shader::Shader(Tegra::Engines::ConstBufferEngineInterface& engine_, ShaderType stage_, |
| 139 | GPUVAddr gpu_addr_, VAddr cpu_addr, VideoCommon::Shader::ProgramCode program_code_, | 142 | GPUVAddr gpu_addr_, VAddr cpu_addr_, ProgramCode program_code_, u32 main_offset_) |
| 140 | u32 main_offset) | 143 | : gpu_addr(gpu_addr_), program_code(std::move(program_code_)), registry(stage_, engine_), |
| 141 | : gpu_addr(gpu_addr_), program_code(std::move(program_code_)), registry(stage, engine), | 144 | shader_ir(program_code, main_offset_, compiler_settings, registry), |
| 142 | shader_ir(program_code, main_offset, compiler_settings, registry), | ||
| 143 | entries(GenerateShaderEntries(shader_ir)) {} | 145 | entries(GenerateShaderEntries(shader_ir)) {} |
| 144 | 146 | ||
| 145 | Shader::~Shader() = default; | 147 | Shader::~Shader() = default; |
| 146 | 148 | ||
| 147 | VKPipelineCache::VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu_, | 149 | VKPipelineCache::VKPipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, |
| 148 | Tegra::Engines::Maxwell3D& maxwell3d_, | 150 | Tegra::Engines::Maxwell3D& maxwell3d_, |
| 149 | Tegra::Engines::KeplerCompute& kepler_compute_, | 151 | Tegra::Engines::KeplerCompute& kepler_compute_, |
| 150 | Tegra::MemoryManager& gpu_memory_, const VKDevice& device_, | 152 | Tegra::MemoryManager& gpu_memory_, const Device& device_, |
| 151 | VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, | 153 | VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, |
| 152 | VKUpdateDescriptorQueue& update_descriptor_queue_, | 154 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 153 | VKRenderPassCache& renderpass_cache_) | 155 | : VideoCommon::ShaderCache<Shader>{rasterizer_}, gpu{gpu_}, maxwell3d{maxwell3d_}, |
| 154 | : VideoCommon::ShaderCache<Shader>{rasterizer}, gpu{gpu_}, maxwell3d{maxwell3d_}, | ||
| 155 | kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_}, | 156 | kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_}, |
| 156 | scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, | 157 | scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, update_descriptor_queue{ |
| 157 | update_descriptor_queue{update_descriptor_queue_}, renderpass_cache{renderpass_cache_} {} | 158 | update_descriptor_queue_} {} |
| 158 | 159 | ||
| 159 | VKPipelineCache::~VKPipelineCache() = default; | 160 | VKPipelineCache::~VKPipelineCache() = default; |
| 160 | 161 | ||
| @@ -199,7 +200,8 @@ std::array<Shader*, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() { | |||
| 199 | } | 200 | } |
| 200 | 201 | ||
| 201 | VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline( | 202 | VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline( |
| 202 | const GraphicsPipelineCacheKey& key, VideoCommon::Shader::AsyncShaders& async_shaders) { | 203 | const GraphicsPipelineCacheKey& key, u32 num_color_buffers, |
| 204 | VideoCommon::Shader::AsyncShaders& async_shaders) { | ||
| 203 | MICROPROFILE_SCOPE(Vulkan_PipelineCache); | 205 | MICROPROFILE_SCOPE(Vulkan_PipelineCache); |
| 204 | 206 | ||
| 205 | if (last_graphics_pipeline && last_graphics_key == key) { | 207 | if (last_graphics_pipeline && last_graphics_key == key) { |
| @@ -215,8 +217,8 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline( | |||
| 215 | LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); | 217 | LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); |
| 216 | const auto [program, bindings] = DecompileShaders(key.fixed_state); | 218 | const auto [program, bindings] = DecompileShaders(key.fixed_state); |
| 217 | async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool, | 219 | async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool, |
| 218 | update_descriptor_queue, renderpass_cache, bindings, | 220 | update_descriptor_queue, bindings, program, key, |
| 219 | program, key); | 221 | num_color_buffers); |
| 220 | } | 222 | } |
| 221 | last_graphics_pipeline = pair->second.get(); | 223 | last_graphics_pipeline = pair->second.get(); |
| 222 | return last_graphics_pipeline; | 224 | return last_graphics_pipeline; |
| @@ -229,8 +231,8 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline( | |||
| 229 | LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); | 231 | LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); |
| 230 | const auto [program, bindings] = DecompileShaders(key.fixed_state); | 232 | const auto [program, bindings] = DecompileShaders(key.fixed_state); |
| 231 | entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool, | 233 | entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool, |
| 232 | update_descriptor_queue, renderpass_cache, key, | 234 | update_descriptor_queue, key, bindings, |
| 233 | bindings, program); | 235 | program, num_color_buffers); |
| 234 | gpu.ShaderNotify().MarkShaderComplete(); | 236 | gpu.ShaderNotify().MarkShaderComplete(); |
| 235 | } | 237 | } |
| 236 | last_graphics_pipeline = entry.get(); | 238 | last_graphics_pipeline = entry.get(); |
| @@ -331,8 +333,7 @@ void VKPipelineCache::OnShaderRemoval(Shader* shader) { | |||
| 331 | std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> | 333 | std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> |
| 332 | VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { | 334 | VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { |
| 333 | Specialization specialization; | 335 | Specialization specialization; |
| 334 | if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points || | 336 | if (fixed_state.topology == Maxwell::PrimitiveTopology::Points) { |
| 335 | device.IsExtExtendedDynamicStateSupported()) { | ||
| 336 | float point_size; | 337 | float point_size; |
| 337 | std::memcpy(&point_size, &fixed_state.point_size, sizeof(float)); | 338 | std::memcpy(&point_size, &fixed_state.point_size, sizeof(float)); |
| 338 | specialization.point_size = point_size; | 339 | specialization.point_size = point_size; |
| @@ -344,6 +345,12 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { | |||
| 344 | specialization.attribute_types[i] = attribute.Type(); | 345 | specialization.attribute_types[i] = attribute.Type(); |
| 345 | } | 346 | } |
| 346 | specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; | 347 | specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; |
| 348 | specialization.early_fragment_tests = fixed_state.early_z; | ||
| 349 | |||
| 350 | // Alpha test | ||
| 351 | specialization.alpha_test_func = | ||
| 352 | FixedPipelineState::UnpackComparisonOp(fixed_state.alpha_test_func.Value()); | ||
| 353 | specialization.alpha_test_ref = Common::BitCast<float>(fixed_state.alpha_test_ref); | ||
| 347 | 354 | ||
| 348 | SPIRVProgram program; | 355 | SPIRVProgram program; |
| 349 | std::vector<VkDescriptorSetLayoutBinding> bindings; | 356 | std::vector<VkDescriptorSetLayoutBinding> bindings; |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index e558e6658..89d635a3d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -19,14 +19,13 @@ | |||
| 19 | #include "video_core/engines/maxwell_3d.h" | 19 | #include "video_core/engines/maxwell_3d.h" |
| 20 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 20 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 21 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 21 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 22 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||
| 23 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | 22 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" |
| 24 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 25 | #include "video_core/shader/async_shaders.h" | 23 | #include "video_core/shader/async_shaders.h" |
| 26 | #include "video_core/shader/memory_util.h" | 24 | #include "video_core/shader/memory_util.h" |
| 27 | #include "video_core/shader/registry.h" | 25 | #include "video_core/shader/registry.h" |
| 28 | #include "video_core/shader/shader_ir.h" | 26 | #include "video_core/shader/shader_ir.h" |
| 29 | #include "video_core/shader_cache.h" | 27 | #include "video_core/shader_cache.h" |
| 28 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 30 | 29 | ||
| 31 | namespace Core { | 30 | namespace Core { |
| 32 | class System; | 31 | class System; |
| @@ -34,10 +33,10 @@ class System; | |||
| 34 | 33 | ||
| 35 | namespace Vulkan { | 34 | namespace Vulkan { |
| 36 | 35 | ||
| 36 | class Device; | ||
| 37 | class RasterizerVulkan; | 37 | class RasterizerVulkan; |
| 38 | class VKComputePipeline; | 38 | class VKComputePipeline; |
| 39 | class VKDescriptorPool; | 39 | class VKDescriptorPool; |
| 40 | class VKDevice; | ||
| 41 | class VKScheduler; | 40 | class VKScheduler; |
| 42 | class VKUpdateDescriptorQueue; | 41 | class VKUpdateDescriptorQueue; |
| 43 | 42 | ||
| @@ -84,9 +83,9 @@ namespace Vulkan { | |||
| 84 | 83 | ||
| 85 | class Shader { | 84 | class Shader { |
| 86 | public: | 85 | public: |
| 87 | explicit Shader(Tegra::Engines::ConstBufferEngineInterface& engine, | 86 | explicit Shader(Tegra::Engines::ConstBufferEngineInterface& engine_, |
| 88 | Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, VAddr cpu_addr, | 87 | Tegra::Engines::ShaderType stage_, GPUVAddr gpu_addr, VAddr cpu_addr_, |
| 89 | VideoCommon::Shader::ProgramCode program_code, u32 main_offset); | 88 | VideoCommon::Shader::ProgramCode program_code, u32 main_offset_); |
| 90 | ~Shader(); | 89 | ~Shader(); |
| 91 | 90 | ||
| 92 | GPUVAddr GetGpuAddr() const { | 91 | GPUVAddr GetGpuAddr() const { |
| @@ -122,15 +121,15 @@ public: | |||
| 122 | explicit VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu, | 121 | explicit VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu, |
| 123 | Tegra::Engines::Maxwell3D& maxwell3d, | 122 | Tegra::Engines::Maxwell3D& maxwell3d, |
| 124 | Tegra::Engines::KeplerCompute& kepler_compute, | 123 | Tegra::Engines::KeplerCompute& kepler_compute, |
| 125 | Tegra::MemoryManager& gpu_memory, const VKDevice& device, | 124 | Tegra::MemoryManager& gpu_memory, const Device& device, |
| 126 | VKScheduler& scheduler, VKDescriptorPool& descriptor_pool, | 125 | VKScheduler& scheduler, VKDescriptorPool& descriptor_pool, |
| 127 | VKUpdateDescriptorQueue& update_descriptor_queue, | 126 | VKUpdateDescriptorQueue& update_descriptor_queue); |
| 128 | VKRenderPassCache& renderpass_cache); | ||
| 129 | ~VKPipelineCache() override; | 127 | ~VKPipelineCache() override; |
| 130 | 128 | ||
| 131 | std::array<Shader*, Maxwell::MaxShaderProgram> GetShaders(); | 129 | std::array<Shader*, Maxwell::MaxShaderProgram> GetShaders(); |
| 132 | 130 | ||
| 133 | VKGraphicsPipeline* GetGraphicsPipeline(const GraphicsPipelineCacheKey& key, | 131 | VKGraphicsPipeline* GetGraphicsPipeline(const GraphicsPipelineCacheKey& key, |
| 132 | u32 num_color_buffers, | ||
| 134 | VideoCommon::Shader::AsyncShaders& async_shaders); | 133 | VideoCommon::Shader::AsyncShaders& async_shaders); |
| 135 | 134 | ||
| 136 | VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key); | 135 | VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key); |
| @@ -149,11 +148,10 @@ private: | |||
| 149 | Tegra::Engines::KeplerCompute& kepler_compute; | 148 | Tegra::Engines::KeplerCompute& kepler_compute; |
| 150 | Tegra::MemoryManager& gpu_memory; | 149 | Tegra::MemoryManager& gpu_memory; |
| 151 | 150 | ||
| 152 | const VKDevice& device; | 151 | const Device& device; |
| 153 | VKScheduler& scheduler; | 152 | VKScheduler& scheduler; |
| 154 | VKDescriptorPool& descriptor_pool; | 153 | VKDescriptorPool& descriptor_pool; |
| 155 | VKUpdateDescriptorQueue& update_descriptor_queue; | 154 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 156 | VKRenderPassCache& renderpass_cache; | ||
| 157 | 155 | ||
| 158 | std::unique_ptr<Shader> null_shader; | 156 | std::unique_ptr<Shader> null_shader; |
| 159 | std::unique_ptr<Shader> null_kernel; | 157 | std::unique_ptr<Shader> null_kernel; |
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index ee2d871e3..7cadd5147 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp | |||
| @@ -7,11 +7,11 @@ | |||
| 7 | #include <utility> | 7 | #include <utility> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 10 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 12 | #include "video_core/renderer_vulkan/vk_resource_pool.h" | 11 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 12 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_device.h" |
| 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 15 | 15 | ||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| @@ -27,7 +27,7 @@ constexpr VkQueryType GetTarget(QueryType type) { | |||
| 27 | 27 | ||
| 28 | } // Anonymous namespace | 28 | } // Anonymous namespace |
| 29 | 29 | ||
| 30 | QueryPool::QueryPool(const VKDevice& device_, VKScheduler& scheduler, QueryType type_) | 30 | QueryPool::QueryPool(const Device& device_, VKScheduler& scheduler, QueryType type_) |
| 31 | : ResourcePool{scheduler.GetMasterSemaphore(), GROW_STEP}, device{device_}, type{type_} {} | 31 | : ResourcePool{scheduler.GetMasterSemaphore(), GROW_STEP}, device{device_}, type{type_} {} |
| 32 | 32 | ||
| 33 | QueryPool::~QueryPool() = default; | 33 | QueryPool::~QueryPool() = default; |
| @@ -66,15 +66,13 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) { | |||
| 66 | usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false; | 66 | usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer, | 69 | VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer_, |
| 70 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, | 70 | Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_, |
| 71 | const VKDevice& device, VKScheduler& scheduler) | 71 | const Device& device_, VKScheduler& scheduler_) |
| 72 | : VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, | 72 | : QueryCacheBase{rasterizer_, maxwell3d_, gpu_memory_}, device{device_}, scheduler{scheduler_}, |
| 73 | HostCounter>{rasterizer, maxwell3d, gpu_memory}, | 73 | query_pools{ |
| 74 | device{device}, scheduler{scheduler}, query_pools{ | 74 | QueryPool{device_, scheduler_, QueryType::SamplesPassed}, |
| 75 | QueryPool{device, scheduler, | 75 | } {} |
| 76 | QueryType::SamplesPassed}, | ||
| 77 | } {} | ||
| 78 | 76 | ||
| 79 | VKQueryCache::~VKQueryCache() { | 77 | VKQueryCache::~VKQueryCache() { |
| 80 | // TODO(Rodrigo): This is a hack to destroy all HostCounter instances before the base class | 78 | // TODO(Rodrigo): This is a hack to destroy all HostCounter instances before the base class |
| @@ -95,12 +93,12 @@ void VKQueryCache::Reserve(QueryType type, std::pair<VkQueryPool, u32> query) { | |||
| 95 | query_pools[static_cast<std::size_t>(type)].Reserve(query); | 93 | query_pools[static_cast<std::size_t>(type)].Reserve(query); |
| 96 | } | 94 | } |
| 97 | 95 | ||
| 98 | HostCounter::HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency, | 96 | HostCounter::HostCounter(VKQueryCache& cache_, std::shared_ptr<HostCounter> dependency_, |
| 99 | QueryType type) | 97 | QueryType type_) |
| 100 | : VideoCommon::HostCounterBase<VKQueryCache, HostCounter>{std::move(dependency)}, cache{cache}, | 98 | : HostCounterBase{std::move(dependency_)}, cache{cache_}, type{type_}, |
| 101 | type{type}, query{cache.AllocateQuery(type)}, tick{cache.Scheduler().CurrentTick()} { | 99 | query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} { |
| 102 | const vk::Device* logical = &cache.Device().GetLogical(); | 100 | const vk::Device* logical = &cache.GetDevice().GetLogical(); |
| 103 | cache.Scheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { | 101 | cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { |
| 104 | logical->ResetQueryPoolEXT(query.first, query.second, 1); | 102 | logical->ResetQueryPoolEXT(query.first, query.second, 1); |
| 105 | cmdbuf.BeginQuery(query.first, query.second, VK_QUERY_CONTROL_PRECISE_BIT); | 103 | cmdbuf.BeginQuery(query.first, query.second, VK_QUERY_CONTROL_PRECISE_BIT); |
| 106 | }); | 104 | }); |
| @@ -111,26 +109,28 @@ HostCounter::~HostCounter() { | |||
| 111 | } | 109 | } |
| 112 | 110 | ||
| 113 | void HostCounter::EndQuery() { | 111 | void HostCounter::EndQuery() { |
| 114 | cache.Scheduler().Record( | 112 | cache.GetScheduler().Record( |
| 115 | [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); }); | 113 | [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); }); |
| 116 | } | 114 | } |
| 117 | 115 | ||
| 118 | u64 HostCounter::BlockingQuery() const { | 116 | u64 HostCounter::BlockingQuery() const { |
| 119 | if (tick >= cache.Scheduler().CurrentTick()) { | 117 | if (tick >= cache.GetScheduler().CurrentTick()) { |
| 120 | cache.Scheduler().Flush(); | 118 | cache.GetScheduler().Flush(); |
| 121 | } | 119 | } |
| 120 | |||
| 122 | u64 data; | 121 | u64 data; |
| 123 | const VkResult result = cache.Device().GetLogical().GetQueryResults( | 122 | const VkResult query_result = cache.GetDevice().GetLogical().GetQueryResults( |
| 124 | query.first, query.second, 1, sizeof(data), &data, sizeof(data), | 123 | query.first, query.second, 1, sizeof(data), &data, sizeof(data), |
| 125 | VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); | 124 | VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); |
| 126 | switch (result) { | 125 | |
| 126 | switch (query_result) { | ||
| 127 | case VK_SUCCESS: | 127 | case VK_SUCCESS: |
| 128 | return data; | 128 | return data; |
| 129 | case VK_ERROR_DEVICE_LOST: | 129 | case VK_ERROR_DEVICE_LOST: |
| 130 | cache.Device().ReportLoss(); | 130 | cache.GetDevice().ReportLoss(); |
| 131 | [[fallthrough]]; | 131 | [[fallthrough]]; |
| 132 | default: | 132 | default: |
| 133 | throw vk::Exception(result); | 133 | throw vk::Exception(query_result); |
| 134 | } | 134 | } |
| 135 | } | 135 | } |
| 136 | 136 | ||
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h index 2e57fb75d..7190946b9 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.h +++ b/src/video_core/renderer_vulkan/vk_query_cache.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "video_core/query_cache.h" | 13 | #include "video_core/query_cache.h" |
| 14 | #include "video_core/renderer_vulkan/vk_resource_pool.h" | 14 | #include "video_core/renderer_vulkan/vk_resource_pool.h" |
| 15 | #include "video_core/renderer_vulkan/wrapper.h" | 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 16 | 16 | ||
| 17 | namespace VideoCore { | 17 | namespace VideoCore { |
| 18 | class RasterizerInterface; | 18 | class RasterizerInterface; |
| @@ -21,8 +21,8 @@ class RasterizerInterface; | |||
| 21 | namespace Vulkan { | 21 | namespace Vulkan { |
| 22 | 22 | ||
| 23 | class CachedQuery; | 23 | class CachedQuery; |
| 24 | class Device; | ||
| 24 | class HostCounter; | 25 | class HostCounter; |
| 25 | class VKDevice; | ||
| 26 | class VKQueryCache; | 26 | class VKQueryCache; |
| 27 | class VKScheduler; | 27 | class VKScheduler; |
| 28 | 28 | ||
| @@ -30,7 +30,7 @@ using CounterStream = VideoCommon::CounterStreamBase<VKQueryCache, HostCounter>; | |||
| 30 | 30 | ||
| 31 | class QueryPool final : public ResourcePool { | 31 | class QueryPool final : public ResourcePool { |
| 32 | public: | 32 | public: |
| 33 | explicit QueryPool(const VKDevice& device, VKScheduler& scheduler, VideoCore::QueryType type); | 33 | explicit QueryPool(const Device& device, VKScheduler& scheduler, VideoCore::QueryType type); |
| 34 | ~QueryPool() override; | 34 | ~QueryPool() override; |
| 35 | 35 | ||
| 36 | std::pair<VkQueryPool, u32> Commit(); | 36 | std::pair<VkQueryPool, u32> Commit(); |
| @@ -43,7 +43,7 @@ protected: | |||
| 43 | private: | 43 | private: |
| 44 | static constexpr std::size_t GROW_STEP = 512; | 44 | static constexpr std::size_t GROW_STEP = 512; |
| 45 | 45 | ||
| 46 | const VKDevice& device; | 46 | const Device& device; |
| 47 | const VideoCore::QueryType type; | 47 | const VideoCore::QueryType type; |
| 48 | 48 | ||
| 49 | std::vector<vk::QueryPool> pools; | 49 | std::vector<vk::QueryPool> pools; |
| @@ -53,33 +53,33 @@ private: | |||
| 53 | class VKQueryCache final | 53 | class VKQueryCache final |
| 54 | : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter> { | 54 | : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter> { |
| 55 | public: | 55 | public: |
| 56 | explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer, | 56 | explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer_, |
| 57 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, | 57 | Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_, |
| 58 | const VKDevice& device, VKScheduler& scheduler); | 58 | const Device& device_, VKScheduler& scheduler_); |
| 59 | ~VKQueryCache(); | 59 | ~VKQueryCache(); |
| 60 | 60 | ||
| 61 | std::pair<VkQueryPool, u32> AllocateQuery(VideoCore::QueryType type); | 61 | std::pair<VkQueryPool, u32> AllocateQuery(VideoCore::QueryType type); |
| 62 | 62 | ||
| 63 | void Reserve(VideoCore::QueryType type, std::pair<VkQueryPool, u32> query); | 63 | void Reserve(VideoCore::QueryType type, std::pair<VkQueryPool, u32> query); |
| 64 | 64 | ||
| 65 | const VKDevice& Device() const noexcept { | 65 | const Device& GetDevice() const noexcept { |
| 66 | return device; | 66 | return device; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | VKScheduler& Scheduler() const noexcept { | 69 | VKScheduler& GetScheduler() const noexcept { |
| 70 | return scheduler; | 70 | return scheduler; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | private: | 73 | private: |
| 74 | const VKDevice& device; | 74 | const Device& device; |
| 75 | VKScheduler& scheduler; | 75 | VKScheduler& scheduler; |
| 76 | std::array<QueryPool, VideoCore::NumQueryTypes> query_pools; | 76 | std::array<QueryPool, VideoCore::NumQueryTypes> query_pools; |
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> { | 79 | class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> { |
| 80 | public: | 80 | public: |
| 81 | explicit HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency, | 81 | explicit HostCounter(VKQueryCache& cache_, std::shared_ptr<HostCounter> dependency_, |
| 82 | VideoCore::QueryType type); | 82 | VideoCore::QueryType type_); |
| 83 | ~HostCounter(); | 83 | ~HostCounter(); |
| 84 | 84 | ||
| 85 | void EndQuery(); | 85 | void EndQuery(); |
| @@ -95,8 +95,8 @@ private: | |||
| 95 | 95 | ||
| 96 | class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> { | 96 | class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> { |
| 97 | public: | 97 | public: |
| 98 | explicit CachedQuery(VKQueryCache&, VideoCore::QueryType, VAddr cpu_addr, u8* host_ptr) | 98 | explicit CachedQuery(VKQueryCache&, VideoCore::QueryType, VAddr cpu_addr_, u8* host_ptr_) |
| 99 | : VideoCommon::CachedQueryBase<HostCounter>{cpu_addr, host_ptr} {} | 99 | : CachedQueryBase{cpu_addr_, host_ptr_} {} |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | } // namespace Vulkan | 102 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f3c2483c8..93fbea510 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "core/settings.h" | 19 | #include "core/settings.h" |
| 20 | #include "video_core/engines/kepler_compute.h" | 20 | #include "video_core/engines/kepler_compute.h" |
| 21 | #include "video_core/engines/maxwell_3d.h" | 21 | #include "video_core/engines/maxwell_3d.h" |
| 22 | #include "video_core/renderer_vulkan/blit_image.h" | ||
| 22 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 23 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 23 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 24 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 24 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 25 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| @@ -26,23 +27,24 @@ | |||
| 26 | #include "video_core/renderer_vulkan/vk_compute_pass.h" | 27 | #include "video_core/renderer_vulkan/vk_compute_pass.h" |
| 27 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" | 28 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" |
| 28 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 29 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 29 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 30 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 30 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 31 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 31 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 32 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 32 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 33 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||
| 34 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" | ||
| 35 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 33 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 36 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 34 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 37 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 35 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 38 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 36 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 39 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 37 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 40 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 41 | #include "video_core/shader_cache.h" | 38 | #include "video_core/shader_cache.h" |
| 39 | #include "video_core/texture_cache/texture_cache.h" | ||
| 40 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 41 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 42 | 42 | ||
| 43 | namespace Vulkan { | 43 | namespace Vulkan { |
| 44 | 44 | ||
| 45 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 45 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 46 | using VideoCommon::ImageViewId; | ||
| 47 | using VideoCommon::ImageViewType; | ||
| 46 | 48 | ||
| 47 | MICROPROFILE_DEFINE(Vulkan_WaitForWorker, "Vulkan", "Wait for worker", MP_RGB(255, 192, 192)); | 49 | MICROPROFILE_DEFINE(Vulkan_WaitForWorker, "Vulkan", "Wait for worker", MP_RGB(255, 192, 192)); |
| 48 | MICROPROFILE_DEFINE(Vulkan_Drawing, "Vulkan", "Record drawing", MP_RGB(192, 128, 128)); | 50 | MICROPROFILE_DEFINE(Vulkan_Drawing, "Vulkan", "Record drawing", MP_RGB(192, 128, 128)); |
| @@ -58,9 +60,9 @@ MICROPROFILE_DEFINE(Vulkan_PipelineCache, "Vulkan", "Pipeline cache", MP_RGB(192 | |||
| 58 | 60 | ||
| 59 | namespace { | 61 | namespace { |
| 60 | 62 | ||
| 61 | constexpr auto ComputeShaderIndex = static_cast<std::size_t>(Tegra::Engines::ShaderType::Compute); | 63 | constexpr auto COMPUTE_SHADER_INDEX = static_cast<size_t>(Tegra::Engines::ShaderType::Compute); |
| 62 | 64 | ||
| 63 | VkViewport GetViewportState(const VKDevice& device, const Maxwell& regs, std::size_t index) { | 65 | VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index) { |
| 64 | const auto& src = regs.viewport_transform[index]; | 66 | const auto& src = regs.viewport_transform[index]; |
| 65 | const float width = src.scale_x * 2.0f; | 67 | const float width = src.scale_x * 2.0f; |
| 66 | const float height = src.scale_y * 2.0f; | 68 | const float height = src.scale_y * 2.0f; |
| @@ -83,7 +85,7 @@ VkViewport GetViewportState(const VKDevice& device, const Maxwell& regs, std::si | |||
| 83 | return viewport; | 85 | return viewport; |
| 84 | } | 86 | } |
| 85 | 87 | ||
| 86 | VkRect2D GetScissorState(const Maxwell& regs, std::size_t index) { | 88 | VkRect2D GetScissorState(const Maxwell& regs, size_t index) { |
| 87 | const auto& src = regs.scissor_test[index]; | 89 | const auto& src = regs.scissor_test[index]; |
| 88 | VkRect2D scissor; | 90 | VkRect2D scissor; |
| 89 | if (src.enable) { | 91 | if (src.enable) { |
| @@ -103,98 +105,122 @@ VkRect2D GetScissorState(const Maxwell& regs, std::size_t index) { | |||
| 103 | std::array<GPUVAddr, Maxwell::MaxShaderProgram> GetShaderAddresses( | 105 | std::array<GPUVAddr, Maxwell::MaxShaderProgram> GetShaderAddresses( |
| 104 | const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { | 106 | const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { |
| 105 | std::array<GPUVAddr, Maxwell::MaxShaderProgram> addresses; | 107 | std::array<GPUVAddr, Maxwell::MaxShaderProgram> addresses; |
| 106 | for (std::size_t i = 0; i < std::size(addresses); ++i) { | 108 | for (size_t i = 0; i < std::size(addresses); ++i) { |
| 107 | addresses[i] = shaders[i] ? shaders[i]->GetGpuAddr() : 0; | 109 | addresses[i] = shaders[i] ? shaders[i]->GetGpuAddr() : 0; |
| 108 | } | 110 | } |
| 109 | return addresses; | 111 | return addresses; |
| 110 | } | 112 | } |
| 111 | 113 | ||
| 112 | void TransitionImages(const std::vector<ImageView>& views, VkPipelineStageFlags pipeline_stage, | 114 | struct TextureHandle { |
| 113 | VkAccessFlags access) { | 115 | constexpr TextureHandle(u32 data, bool via_header_index) { |
| 114 | for (auto& [view, layout] : views) { | 116 | const Tegra::Texture::TextureHandle handle{data}; |
| 115 | view->Transition(*layout, pipeline_stage, access); | 117 | image = handle.tic_id; |
| 118 | sampler = via_header_index ? image : handle.tsc_id.Value(); | ||
| 116 | } | 119 | } |
| 117 | } | 120 | |
| 121 | u32 image; | ||
| 122 | u32 sampler; | ||
| 123 | }; | ||
| 118 | 124 | ||
| 119 | template <typename Engine, typename Entry> | 125 | template <typename Engine, typename Entry> |
| 120 | Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry, | 126 | TextureHandle GetTextureInfo(const Engine& engine, bool via_header_index, const Entry& entry, |
| 121 | std::size_t stage, std::size_t index = 0) { | 127 | size_t stage, size_t index = 0) { |
| 122 | const auto stage_type = static_cast<Tegra::Engines::ShaderType>(stage); | 128 | const auto shader_type = static_cast<Tegra::Engines::ShaderType>(stage); |
| 123 | if constexpr (std::is_same_v<Entry, SamplerEntry>) { | 129 | if constexpr (std::is_same_v<Entry, SamplerEntry>) { |
| 124 | if (entry.is_separated) { | 130 | if (entry.is_separated) { |
| 125 | const u32 buffer_1 = entry.buffer; | 131 | const u32 buffer_1 = entry.buffer; |
| 126 | const u32 buffer_2 = entry.secondary_buffer; | 132 | const u32 buffer_2 = entry.secondary_buffer; |
| 127 | const u32 offset_1 = entry.offset; | 133 | const u32 offset_1 = entry.offset; |
| 128 | const u32 offset_2 = entry.secondary_offset; | 134 | const u32 offset_2 = entry.secondary_offset; |
| 129 | const u32 handle_1 = engine.AccessConstBuffer32(stage_type, buffer_1, offset_1); | 135 | const u32 handle_1 = engine.AccessConstBuffer32(shader_type, buffer_1, offset_1); |
| 130 | const u32 handle_2 = engine.AccessConstBuffer32(stage_type, buffer_2, offset_2); | 136 | const u32 handle_2 = engine.AccessConstBuffer32(shader_type, buffer_2, offset_2); |
| 131 | return engine.GetTextureInfo(handle_1 | handle_2); | 137 | return TextureHandle(handle_1 | handle_2, via_header_index); |
| 132 | } | 138 | } |
| 133 | } | 139 | } |
| 134 | if (entry.is_bindless) { | 140 | if (entry.is_bindless) { |
| 135 | const auto tex_handle = engine.AccessConstBuffer32(stage_type, entry.buffer, entry.offset); | 141 | const u32 raw = engine.AccessConstBuffer32(shader_type, entry.buffer, entry.offset); |
| 136 | return engine.GetTextureInfo(tex_handle); | 142 | return TextureHandle(raw, via_header_index); |
| 137 | } | ||
| 138 | const auto& gpu_profile = engine.AccessGuestDriverProfile(); | ||
| 139 | const u32 entry_offset = static_cast<u32>(index * gpu_profile.GetTextureHandlerSize()); | ||
| 140 | const u32 offset = entry.offset + entry_offset; | ||
| 141 | if constexpr (std::is_same_v<Engine, Tegra::Engines::Maxwell3D>) { | ||
| 142 | return engine.GetStageTexture(stage_type, offset); | ||
| 143 | } else { | ||
| 144 | return engine.GetTexture(offset); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | /// @brief Determine if an attachment to be updated has to preserve contents | ||
| 149 | /// @param is_clear True when a clear is being executed | ||
| 150 | /// @param regs 3D registers | ||
| 151 | /// @return True when the contents have to be preserved | ||
| 152 | bool HasToPreserveColorContents(bool is_clear, const Maxwell& regs) { | ||
| 153 | if (!is_clear) { | ||
| 154 | return true; | ||
| 155 | } | ||
| 156 | // First we have to make sure all clear masks are enabled. | ||
| 157 | if (!regs.clear_buffers.R || !regs.clear_buffers.G || !regs.clear_buffers.B || | ||
| 158 | !regs.clear_buffers.A) { | ||
| 159 | return true; | ||
| 160 | } | ||
| 161 | // If scissors are disabled, the whole screen is cleared | ||
| 162 | if (!regs.clear_flags.scissor) { | ||
| 163 | return false; | ||
| 164 | } | 143 | } |
| 165 | // Then we have to confirm scissor testing clears the whole image | 144 | const u32 buffer = engine.GetBoundBuffer(); |
| 166 | const std::size_t index = regs.clear_buffers.RT; | 145 | const u64 offset = (entry.offset + index) * sizeof(u32); |
| 167 | const auto& scissor = regs.scissor_test[0]; | 146 | return TextureHandle(engine.AccessConstBuffer32(shader_type, buffer, offset), via_header_index); |
| 168 | return scissor.min_x > 0 || scissor.min_y > 0 || scissor.max_x < regs.rt[index].width || | ||
| 169 | scissor.max_y < regs.rt[index].height; | ||
| 170 | } | 147 | } |
| 171 | 148 | ||
| 172 | /// @brief Determine if an attachment to be updated has to preserve contents | 149 | template <size_t N> |
| 173 | /// @param is_clear True when a clear is being executed | ||
| 174 | /// @param regs 3D registers | ||
| 175 | /// @return True when the contents have to be preserved | ||
| 176 | bool HasToPreserveDepthContents(bool is_clear, const Maxwell& regs) { | ||
| 177 | // If we are not clearing, the contents have to be preserved | ||
| 178 | if (!is_clear) { | ||
| 179 | return true; | ||
| 180 | } | ||
| 181 | // For depth stencil clears we only have to confirm scissor test covers the whole image | ||
| 182 | if (!regs.clear_flags.scissor) { | ||
| 183 | return false; | ||
| 184 | } | ||
| 185 | // Make sure the clear cover the whole image | ||
| 186 | const auto& scissor = regs.scissor_test[0]; | ||
| 187 | return scissor.min_x > 0 || scissor.min_y > 0 || scissor.max_x < regs.zeta_width || | ||
| 188 | scissor.max_y < regs.zeta_height; | ||
| 189 | } | ||
| 190 | |||
| 191 | template <std::size_t N> | ||
| 192 | std::array<VkDeviceSize, N> ExpandStrides(const std::array<u16, N>& strides) { | 150 | std::array<VkDeviceSize, N> ExpandStrides(const std::array<u16, N>& strides) { |
| 193 | std::array<VkDeviceSize, N> expanded; | 151 | std::array<VkDeviceSize, N> expanded; |
| 194 | std::copy(strides.begin(), strides.end(), expanded.begin()); | 152 | std::copy(strides.begin(), strides.end(), expanded.begin()); |
| 195 | return expanded; | 153 | return expanded; |
| 196 | } | 154 | } |
| 197 | 155 | ||
| 156 | ImageViewType ImageViewTypeFromEntry(const SamplerEntry& entry) { | ||
| 157 | if (entry.is_buffer) { | ||
| 158 | return ImageViewType::e2D; | ||
| 159 | } | ||
| 160 | switch (entry.type) { | ||
| 161 | case Tegra::Shader::TextureType::Texture1D: | ||
| 162 | return entry.is_array ? ImageViewType::e1DArray : ImageViewType::e1D; | ||
| 163 | case Tegra::Shader::TextureType::Texture2D: | ||
| 164 | return entry.is_array ? ImageViewType::e2DArray : ImageViewType::e2D; | ||
| 165 | case Tegra::Shader::TextureType::Texture3D: | ||
| 166 | return ImageViewType::e3D; | ||
| 167 | case Tegra::Shader::TextureType::TextureCube: | ||
| 168 | return entry.is_array ? ImageViewType::CubeArray : ImageViewType::Cube; | ||
| 169 | } | ||
| 170 | UNREACHABLE(); | ||
| 171 | return ImageViewType::e2D; | ||
| 172 | } | ||
| 173 | |||
| 174 | ImageViewType ImageViewTypeFromEntry(const ImageEntry& entry) { | ||
| 175 | switch (entry.type) { | ||
| 176 | case Tegra::Shader::ImageType::Texture1D: | ||
| 177 | return ImageViewType::e1D; | ||
| 178 | case Tegra::Shader::ImageType::Texture1DArray: | ||
| 179 | return ImageViewType::e1DArray; | ||
| 180 | case Tegra::Shader::ImageType::Texture2D: | ||
| 181 | return ImageViewType::e2D; | ||
| 182 | case Tegra::Shader::ImageType::Texture2DArray: | ||
| 183 | return ImageViewType::e2DArray; | ||
| 184 | case Tegra::Shader::ImageType::Texture3D: | ||
| 185 | return ImageViewType::e3D; | ||
| 186 | case Tegra::Shader::ImageType::TextureBuffer: | ||
| 187 | return ImageViewType::Buffer; | ||
| 188 | } | ||
| 189 | UNREACHABLE(); | ||
| 190 | return ImageViewType::e2D; | ||
| 191 | } | ||
| 192 | |||
| 193 | void PushImageDescriptors(const ShaderEntries& entries, TextureCache& texture_cache, | ||
| 194 | VKUpdateDescriptorQueue& update_descriptor_queue, | ||
| 195 | ImageViewId*& image_view_id_ptr, VkSampler*& sampler_ptr) { | ||
| 196 | for ([[maybe_unused]] const auto& entry : entries.uniform_texels) { | ||
| 197 | const ImageViewId image_view_id = *image_view_id_ptr++; | ||
| 198 | const ImageView& image_view = texture_cache.GetImageView(image_view_id); | ||
| 199 | update_descriptor_queue.AddTexelBuffer(image_view.BufferView()); | ||
| 200 | } | ||
| 201 | for (const auto& entry : entries.samplers) { | ||
| 202 | for (size_t i = 0; i < entry.size; ++i) { | ||
| 203 | const VkSampler sampler = *sampler_ptr++; | ||
| 204 | const ImageViewId image_view_id = *image_view_id_ptr++; | ||
| 205 | const ImageView& image_view = texture_cache.GetImageView(image_view_id); | ||
| 206 | const VkImageView handle = image_view.Handle(ImageViewTypeFromEntry(entry)); | ||
| 207 | update_descriptor_queue.AddSampledImage(handle, sampler); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | for ([[maybe_unused]] const auto& entry : entries.storage_texels) { | ||
| 211 | const ImageViewId image_view_id = *image_view_id_ptr++; | ||
| 212 | const ImageView& image_view = texture_cache.GetImageView(image_view_id); | ||
| 213 | update_descriptor_queue.AddTexelBuffer(image_view.BufferView()); | ||
| 214 | } | ||
| 215 | for (const auto& entry : entries.images) { | ||
| 216 | // TODO: Mark as modified | ||
| 217 | const ImageViewId image_view_id = *image_view_id_ptr++; | ||
| 218 | const ImageView& image_view = texture_cache.GetImageView(image_view_id); | ||
| 219 | const VkImageView handle = image_view.Handle(ImageViewTypeFromEntry(entry)); | ||
| 220 | update_descriptor_queue.AddImage(handle); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 198 | } // Anonymous namespace | 224 | } // Anonymous namespace |
| 199 | 225 | ||
| 200 | class BufferBindings final { | 226 | class BufferBindings final { |
| @@ -213,7 +239,7 @@ public: | |||
| 213 | index.type = type; | 239 | index.type = type; |
| 214 | } | 240 | } |
| 215 | 241 | ||
| 216 | void Bind(const VKDevice& device, VKScheduler& scheduler) const { | 242 | void Bind(const Device& device, VKScheduler& scheduler) const { |
| 217 | // Use this large switch case to avoid dispatching more memory in the record lambda than | 243 | // Use this large switch case to avoid dispatching more memory in the record lambda than |
| 218 | // what we need. It looks horrible, but it's the best we can do on standard C++. | 244 | // what we need. It looks horrible, but it's the best we can do on standard C++. |
| 219 | switch (vertex.num_buffers) { | 245 | switch (vertex.num_buffers) { |
| @@ -290,7 +316,7 @@ public: | |||
| 290 | private: | 316 | private: |
| 291 | // Some of these fields are intentionally left uninitialized to avoid initializing them twice. | 317 | // Some of these fields are intentionally left uninitialized to avoid initializing them twice. |
| 292 | struct { | 318 | struct { |
| 293 | std::size_t num_buffers = 0; | 319 | size_t num_buffers = 0; |
| 294 | std::array<VkBuffer, Maxwell::NumVertexArrays> buffers; | 320 | std::array<VkBuffer, Maxwell::NumVertexArrays> buffers; |
| 295 | std::array<VkDeviceSize, Maxwell::NumVertexArrays> offsets; | 321 | std::array<VkDeviceSize, Maxwell::NumVertexArrays> offsets; |
| 296 | std::array<VkDeviceSize, Maxwell::NumVertexArrays> sizes; | 322 | std::array<VkDeviceSize, Maxwell::NumVertexArrays> sizes; |
| @@ -303,8 +329,8 @@ private: | |||
| 303 | VkIndexType type; | 329 | VkIndexType type; |
| 304 | } index; | 330 | } index; |
| 305 | 331 | ||
| 306 | template <std::size_t N> | 332 | template <size_t N> |
| 307 | void BindStatic(const VKDevice& device, VKScheduler& scheduler) const { | 333 | void BindStatic(const Device& device, VKScheduler& scheduler) const { |
| 308 | if (device.IsExtExtendedDynamicStateSupported()) { | 334 | if (device.IsExtExtendedDynamicStateSupported()) { |
| 309 | if (index.buffer) { | 335 | if (index.buffer) { |
| 310 | BindStatic<N, true, true>(scheduler); | 336 | BindStatic<N, true, true>(scheduler); |
| @@ -320,7 +346,7 @@ private: | |||
| 320 | } | 346 | } |
| 321 | } | 347 | } |
| 322 | 348 | ||
| 323 | template <std::size_t N, bool is_indexed, bool has_extended_dynamic_state> | 349 | template <size_t N, bool is_indexed, bool has_extended_dynamic_state> |
| 324 | void BindStatic(VKScheduler& scheduler) const { | 350 | void BindStatic(VKScheduler& scheduler) const { |
| 325 | static_assert(N <= Maxwell::NumVertexArrays); | 351 | static_assert(N <= Maxwell::NumVertexArrays); |
| 326 | if constexpr (N == 0) { | 352 | if constexpr (N == 0) { |
| @@ -380,28 +406,31 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf) const { | |||
| 380 | } | 406 | } |
| 381 | } | 407 | } |
| 382 | 408 | ||
| 383 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu_, | 409 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 384 | Tegra::MemoryManager& gpu_memory_, | 410 | Tegra::MemoryManager& gpu_memory_, |
| 385 | Core::Memory::Memory& cpu_memory, VKScreenInfo& screen_info_, | 411 | Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, |
| 386 | const VKDevice& device_, VKMemoryManager& memory_manager_, | 412 | const Device& device_, VKMemoryManager& memory_manager_, |
| 387 | StateTracker& state_tracker_, VKScheduler& scheduler_) | 413 | StateTracker& state_tracker_, VKScheduler& scheduler_) |
| 388 | : RasterizerAccelerated(cpu_memory), gpu(gpu_), gpu_memory(gpu_memory_), | 414 | : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, |
| 389 | maxwell3d(gpu.Maxwell3D()), kepler_compute(gpu.KeplerCompute()), screen_info(screen_info_), | 415 | gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, |
| 390 | device(device_), memory_manager(memory_manager_), state_tracker(state_tracker_), | 416 | screen_info{screen_info_}, device{device_}, memory_manager{memory_manager_}, |
| 391 | scheduler(scheduler_), staging_pool(device, memory_manager, scheduler), | 417 | state_tracker{state_tracker_}, scheduler{scheduler_}, stream_buffer(device, scheduler), |
| 392 | descriptor_pool(device, scheduler_), update_descriptor_queue(device, scheduler), | 418 | staging_pool(device, memory_manager, scheduler), descriptor_pool(device, scheduler), |
| 393 | renderpass_cache(device), | 419 | update_descriptor_queue(device, scheduler), |
| 420 | blit_image(device, scheduler, state_tracker, descriptor_pool), | ||
| 394 | quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 421 | quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 395 | quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 422 | quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 396 | uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 423 | uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 397 | texture_cache(*this, maxwell3d, gpu_memory, device, memory_manager, scheduler, staging_pool), | 424 | texture_cache_runtime{device, scheduler, memory_manager, staging_pool, blit_image}, |
| 425 | texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), | ||
| 398 | pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, | 426 | pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, |
| 399 | descriptor_pool, update_descriptor_queue, renderpass_cache), | 427 | descriptor_pool, update_descriptor_queue), |
| 400 | buffer_cache(*this, gpu_memory, cpu_memory, device, memory_manager, scheduler, staging_pool), | 428 | buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_manager, scheduler, stream_buffer, |
| 401 | sampler_cache(device), query_cache(*this, maxwell3d, gpu_memory, device, scheduler), | 429 | staging_pool), |
| 430 | query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, | ||
| 402 | fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device, | 431 | fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device, |
| 403 | scheduler), | 432 | scheduler), |
| 404 | wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window) { | 433 | wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { |
| 405 | scheduler.SetQueryCache(query_cache); | 434 | scheduler.SetQueryCache(query_cache); |
| 406 | if (device.UseAsynchronousShaders()) { | 435 | if (device.UseAsynchronousShaders()) { |
| 407 | async_shaders.AllocateWorkers(); | 436 | async_shaders.AllocateWorkers(); |
| @@ -427,9 +456,10 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { | |||
| 427 | const DrawParameters draw_params = | 456 | const DrawParameters draw_params = |
| 428 | SetupGeometry(key.fixed_state, buffer_bindings, is_indexed, is_instanced); | 457 | SetupGeometry(key.fixed_state, buffer_bindings, is_indexed, is_instanced); |
| 429 | 458 | ||
| 430 | update_descriptor_queue.Acquire(); | 459 | auto lock = texture_cache.AcquireLock(); |
| 431 | sampled_views.clear(); | 460 | texture_cache.SynchronizeGraphicsDescriptors(); |
| 432 | image_views.clear(); | 461 | |
| 462 | texture_cache.UpdateRenderTargets(false); | ||
| 433 | 463 | ||
| 434 | const auto shaders = pipeline_cache.GetShaders(); | 464 | const auto shaders = pipeline_cache.GetShaders(); |
| 435 | key.shaders = GetShaderAddresses(shaders); | 465 | key.shaders = GetShaderAddresses(shaders); |
| @@ -437,30 +467,24 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { | |||
| 437 | 467 | ||
| 438 | buffer_cache.Unmap(); | 468 | buffer_cache.Unmap(); |
| 439 | 469 | ||
| 440 | const Texceptions texceptions = UpdateAttachments(false); | 470 | const Framebuffer* const framebuffer = texture_cache.GetFramebuffer(); |
| 441 | SetupImageTransitions(texceptions, color_attachments, zeta_attachment); | 471 | key.renderpass = framebuffer->RenderPass(); |
| 442 | |||
| 443 | key.renderpass_params = GetRenderPassParams(texceptions); | ||
| 444 | key.padding = 0; | ||
| 445 | 472 | ||
| 446 | auto* pipeline = pipeline_cache.GetGraphicsPipeline(key, async_shaders); | 473 | auto* const pipeline = |
| 474 | pipeline_cache.GetGraphicsPipeline(key, framebuffer->NumColorBuffers(), async_shaders); | ||
| 447 | if (pipeline == nullptr || pipeline->GetHandle() == VK_NULL_HANDLE) { | 475 | if (pipeline == nullptr || pipeline->GetHandle() == VK_NULL_HANDLE) { |
| 448 | // Async graphics pipeline was not ready. | 476 | // Async graphics pipeline was not ready. |
| 449 | return; | 477 | return; |
| 450 | } | 478 | } |
| 451 | 479 | ||
| 452 | scheduler.BindGraphicsPipeline(pipeline->GetHandle()); | ||
| 453 | |||
| 454 | const auto renderpass = pipeline->GetRenderPass(); | ||
| 455 | const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass); | ||
| 456 | scheduler.RequestRenderpass(renderpass, framebuffer, render_area); | ||
| 457 | |||
| 458 | UpdateDynamicStates(); | ||
| 459 | |||
| 460 | buffer_bindings.Bind(device, scheduler); | 480 | buffer_bindings.Bind(device, scheduler); |
| 461 | 481 | ||
| 462 | BeginTransformFeedback(); | 482 | BeginTransformFeedback(); |
| 463 | 483 | ||
| 484 | scheduler.RequestRenderpass(framebuffer); | ||
| 485 | scheduler.BindGraphicsPipeline(pipeline->GetHandle()); | ||
| 486 | UpdateDynamicStates(); | ||
| 487 | |||
| 464 | const auto pipeline_layout = pipeline->GetLayout(); | 488 | const auto pipeline_layout = pipeline->GetLayout(); |
| 465 | const auto descriptor_set = pipeline->CommitDescriptorSet(); | 489 | const auto descriptor_set = pipeline->CommitDescriptorSet(); |
| 466 | scheduler.Record([pipeline_layout, descriptor_set, draw_params](vk::CommandBuffer cmdbuf) { | 490 | scheduler.Record([pipeline_layout, descriptor_set, draw_params](vk::CommandBuffer cmdbuf) { |
| @@ -481,9 +505,6 @@ void RasterizerVulkan::Clear() { | |||
| 481 | return; | 505 | return; |
| 482 | } | 506 | } |
| 483 | 507 | ||
| 484 | sampled_views.clear(); | ||
| 485 | image_views.clear(); | ||
| 486 | |||
| 487 | query_cache.UpdateCounters(); | 508 | query_cache.UpdateCounters(); |
| 488 | 509 | ||
| 489 | const auto& regs = maxwell3d.regs; | 510 | const auto& regs = maxwell3d.regs; |
| @@ -495,20 +516,24 @@ void RasterizerVulkan::Clear() { | |||
| 495 | return; | 516 | return; |
| 496 | } | 517 | } |
| 497 | 518 | ||
| 498 | [[maybe_unused]] const auto texceptions = UpdateAttachments(true); | 519 | auto lock = texture_cache.AcquireLock(); |
| 499 | DEBUG_ASSERT(texceptions.none()); | 520 | texture_cache.UpdateRenderTargets(true); |
| 500 | SetupImageTransitions(0, color_attachments, zeta_attachment); | 521 | const Framebuffer* const framebuffer = texture_cache.GetFramebuffer(); |
| 501 | 522 | const VkExtent2D render_area = framebuffer->RenderArea(); | |
| 502 | const VkRenderPass renderpass = renderpass_cache.GetRenderPass(GetRenderPassParams(0)); | 523 | scheduler.RequestRenderpass(framebuffer); |
| 503 | const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass); | ||
| 504 | scheduler.RequestRenderpass(renderpass, framebuffer, render_area); | ||
| 505 | 524 | ||
| 506 | VkClearRect clear_rect; | 525 | VkClearRect clear_rect{ |
| 507 | clear_rect.baseArrayLayer = regs.clear_buffers.layer; | 526 | .rect = GetScissorState(regs, 0), |
| 508 | clear_rect.layerCount = 1; | 527 | .baseArrayLayer = regs.clear_buffers.layer, |
| 509 | clear_rect.rect = GetScissorState(regs, 0); | 528 | .layerCount = 1, |
| 510 | clear_rect.rect.extent.width = std::min(clear_rect.rect.extent.width, render_area.width); | 529 | }; |
| 511 | clear_rect.rect.extent.height = std::min(clear_rect.rect.extent.height, render_area.height); | 530 | if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) { |
| 531 | return; | ||
| 532 | } | ||
| 533 | clear_rect.rect.extent = VkExtent2D{ | ||
| 534 | .width = std::min(clear_rect.rect.extent.width, render_area.width), | ||
| 535 | .height = std::min(clear_rect.rect.extent.height, render_area.height), | ||
| 536 | }; | ||
| 512 | 537 | ||
| 513 | if (use_color) { | 538 | if (use_color) { |
| 514 | VkClearValue clear_value; | 539 | VkClearValue clear_value; |
| @@ -549,9 +574,6 @@ void RasterizerVulkan::Clear() { | |||
| 549 | 574 | ||
| 550 | void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) { | 575 | void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) { |
| 551 | MICROPROFILE_SCOPE(Vulkan_Compute); | 576 | MICROPROFILE_SCOPE(Vulkan_Compute); |
| 552 | update_descriptor_queue.Acquire(); | ||
| 553 | sampled_views.clear(); | ||
| 554 | image_views.clear(); | ||
| 555 | 577 | ||
| 556 | query_cache.UpdateCounters(); | 578 | query_cache.UpdateCounters(); |
| 557 | 579 | ||
| @@ -570,30 +592,46 @@ void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) { | |||
| 570 | // Compute dispatches can't be executed inside a renderpass | 592 | // Compute dispatches can't be executed inside a renderpass |
| 571 | scheduler.RequestOutsideRenderPassOperationContext(); | 593 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 572 | 594 | ||
| 573 | buffer_cache.Map(CalculateComputeStreamBufferSize()); | 595 | image_view_indices.clear(); |
| 596 | sampler_handles.clear(); | ||
| 597 | |||
| 598 | auto lock = texture_cache.AcquireLock(); | ||
| 599 | texture_cache.SynchronizeComputeDescriptors(); | ||
| 574 | 600 | ||
| 575 | const auto& entries = pipeline.GetEntries(); | 601 | const auto& entries = pipeline.GetEntries(); |
| 576 | SetupComputeConstBuffers(entries); | ||
| 577 | SetupComputeGlobalBuffers(entries); | ||
| 578 | SetupComputeUniformTexels(entries); | 602 | SetupComputeUniformTexels(entries); |
| 579 | SetupComputeTextures(entries); | 603 | SetupComputeTextures(entries); |
| 580 | SetupComputeStorageTexels(entries); | 604 | SetupComputeStorageTexels(entries); |
| 581 | SetupComputeImages(entries); | 605 | SetupComputeImages(entries); |
| 582 | 606 | ||
| 583 | buffer_cache.Unmap(); | 607 | const std::span indices_span(image_view_indices.data(), image_view_indices.size()); |
| 608 | texture_cache.FillComputeImageViews(indices_span, image_view_ids); | ||
| 609 | |||
| 610 | buffer_cache.Map(CalculateComputeStreamBufferSize()); | ||
| 611 | |||
| 612 | update_descriptor_queue.Acquire(); | ||
| 613 | |||
| 614 | SetupComputeConstBuffers(entries); | ||
| 615 | SetupComputeGlobalBuffers(entries); | ||
| 616 | |||
| 617 | ImageViewId* image_view_id_ptr = image_view_ids.data(); | ||
| 618 | VkSampler* sampler_ptr = sampler_handles.data(); | ||
| 619 | PushImageDescriptors(entries, texture_cache, update_descriptor_queue, image_view_id_ptr, | ||
| 620 | sampler_ptr); | ||
| 584 | 621 | ||
| 585 | TransitionImages(sampled_views, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 622 | buffer_cache.Unmap(); |
| 586 | VK_ACCESS_SHADER_READ_BIT); | ||
| 587 | TransitionImages(image_views, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 588 | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); | ||
| 589 | 623 | ||
| 624 | const VkPipeline pipeline_handle = pipeline.GetHandle(); | ||
| 625 | const VkPipelineLayout pipeline_layout = pipeline.GetLayout(); | ||
| 626 | const VkDescriptorSet descriptor_set = pipeline.CommitDescriptorSet(); | ||
| 590 | scheduler.Record([grid_x = launch_desc.grid_dim_x, grid_y = launch_desc.grid_dim_y, | 627 | scheduler.Record([grid_x = launch_desc.grid_dim_x, grid_y = launch_desc.grid_dim_y, |
| 591 | grid_z = launch_desc.grid_dim_z, pipeline_handle = pipeline.GetHandle(), | 628 | grid_z = launch_desc.grid_dim_z, pipeline_handle, pipeline_layout, |
| 592 | layout = pipeline.GetLayout(), | 629 | descriptor_set](vk::CommandBuffer cmdbuf) { |
| 593 | descriptor_set = pipeline.CommitDescriptorSet()](vk::CommandBuffer cmdbuf) { | ||
| 594 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_handle); | 630 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_handle); |
| 595 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, DESCRIPTOR_SET, | 631 | if (descriptor_set) { |
| 596 | descriptor_set, {}); | 632 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, |
| 633 | DESCRIPTOR_SET, descriptor_set, nullptr); | ||
| 634 | } | ||
| 597 | cmdbuf.Dispatch(grid_x, grid_y, grid_z); | 635 | cmdbuf.Dispatch(grid_x, grid_y, grid_z); |
| 598 | }); | 636 | }); |
| 599 | } | 637 | } |
| @@ -613,7 +651,10 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) { | |||
| 613 | if (addr == 0 || size == 0) { | 651 | if (addr == 0 || size == 0) { |
| 614 | return; | 652 | return; |
| 615 | } | 653 | } |
| 616 | texture_cache.FlushRegion(addr, size); | 654 | { |
| 655 | auto lock = texture_cache.AcquireLock(); | ||
| 656 | texture_cache.DownloadMemory(addr, size); | ||
| 657 | } | ||
| 617 | buffer_cache.FlushRegion(addr, size); | 658 | buffer_cache.FlushRegion(addr, size); |
| 618 | query_cache.FlushRegion(addr, size); | 659 | query_cache.FlushRegion(addr, size); |
| 619 | } | 660 | } |
| @@ -622,14 +663,18 @@ bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) { | |||
| 622 | if (!Settings::IsGPULevelHigh()) { | 663 | if (!Settings::IsGPULevelHigh()) { |
| 623 | return buffer_cache.MustFlushRegion(addr, size); | 664 | return buffer_cache.MustFlushRegion(addr, size); |
| 624 | } | 665 | } |
| 625 | return texture_cache.MustFlushRegion(addr, size) || buffer_cache.MustFlushRegion(addr, size); | 666 | return texture_cache.IsRegionGpuModified(addr, size) || |
| 667 | buffer_cache.MustFlushRegion(addr, size); | ||
| 626 | } | 668 | } |
| 627 | 669 | ||
| 628 | void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) { | 670 | void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) { |
| 629 | if (addr == 0 || size == 0) { | 671 | if (addr == 0 || size == 0) { |
| 630 | return; | 672 | return; |
| 631 | } | 673 | } |
| 632 | texture_cache.InvalidateRegion(addr, size); | 674 | { |
| 675 | auto lock = texture_cache.AcquireLock(); | ||
| 676 | texture_cache.WriteMemory(addr, size); | ||
| 677 | } | ||
| 633 | pipeline_cache.InvalidateRegion(addr, size); | 678 | pipeline_cache.InvalidateRegion(addr, size); |
| 634 | buffer_cache.InvalidateRegion(addr, size); | 679 | buffer_cache.InvalidateRegion(addr, size); |
| 635 | query_cache.InvalidateRegion(addr, size); | 680 | query_cache.InvalidateRegion(addr, size); |
| @@ -639,17 +684,28 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) { | |||
| 639 | if (addr == 0 || size == 0) { | 684 | if (addr == 0 || size == 0) { |
| 640 | return; | 685 | return; |
| 641 | } | 686 | } |
| 642 | texture_cache.OnCPUWrite(addr, size); | 687 | { |
| 688 | auto lock = texture_cache.AcquireLock(); | ||
| 689 | texture_cache.WriteMemory(addr, size); | ||
| 690 | } | ||
| 643 | pipeline_cache.OnCPUWrite(addr, size); | 691 | pipeline_cache.OnCPUWrite(addr, size); |
| 644 | buffer_cache.OnCPUWrite(addr, size); | 692 | buffer_cache.OnCPUWrite(addr, size); |
| 645 | } | 693 | } |
| 646 | 694 | ||
| 647 | void RasterizerVulkan::SyncGuestHost() { | 695 | void RasterizerVulkan::SyncGuestHost() { |
| 648 | texture_cache.SyncGuestHost(); | ||
| 649 | buffer_cache.SyncGuestHost(); | 696 | buffer_cache.SyncGuestHost(); |
| 650 | pipeline_cache.SyncGuestHost(); | 697 | pipeline_cache.SyncGuestHost(); |
| 651 | } | 698 | } |
| 652 | 699 | ||
| 700 | void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) { | ||
| 701 | { | ||
| 702 | auto lock = texture_cache.AcquireLock(); | ||
| 703 | texture_cache.UnmapMemory(addr, size); | ||
| 704 | } | ||
| 705 | buffer_cache.OnCPUWrite(addr, size); | ||
| 706 | pipeline_cache.OnCPUWrite(addr, size); | ||
| 707 | } | ||
| 708 | |||
| 653 | void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { | 709 | void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { |
| 654 | if (!gpu.IsAsync()) { | 710 | if (!gpu.IsAsync()) { |
| 655 | gpu_memory.Write<u32>(addr, value); | 711 | gpu_memory.Write<u32>(addr, value); |
| @@ -700,6 +756,14 @@ void RasterizerVulkan::WaitForIdle() { | |||
| 700 | }); | 756 | }); |
| 701 | } | 757 | } |
| 702 | 758 | ||
| 759 | void RasterizerVulkan::FragmentBarrier() { | ||
| 760 | // We already put barriers when a render pass finishes | ||
| 761 | } | ||
| 762 | |||
| 763 | void RasterizerVulkan::TiledCacheBarrier() { | ||
| 764 | // TODO: Implementing tiled barriers requires rewriting a good chunk of the Vulkan backend | ||
| 765 | } | ||
| 766 | |||
| 703 | void RasterizerVulkan::FlushCommands() { | 767 | void RasterizerVulkan::FlushCommands() { |
| 704 | if (draw_counter > 0) { | 768 | if (draw_counter > 0) { |
| 705 | draw_counter = 0; | 769 | draw_counter = 0; |
| @@ -710,14 +774,20 @@ void RasterizerVulkan::FlushCommands() { | |||
| 710 | void RasterizerVulkan::TickFrame() { | 774 | void RasterizerVulkan::TickFrame() { |
| 711 | draw_counter = 0; | 775 | draw_counter = 0; |
| 712 | update_descriptor_queue.TickFrame(); | 776 | update_descriptor_queue.TickFrame(); |
| 777 | fence_manager.TickFrame(); | ||
| 713 | buffer_cache.TickFrame(); | 778 | buffer_cache.TickFrame(); |
| 714 | staging_pool.TickFrame(); | 779 | staging_pool.TickFrame(); |
| 780 | { | ||
| 781 | auto lock = texture_cache.AcquireLock(); | ||
| 782 | texture_cache.TickFrame(); | ||
| 783 | } | ||
| 715 | } | 784 | } |
| 716 | 785 | ||
| 717 | bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, | 786 | bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, |
| 718 | const Tegra::Engines::Fermi2D::Regs::Surface& dst, | 787 | const Tegra::Engines::Fermi2D::Surface& dst, |
| 719 | const Tegra::Engines::Fermi2D::Config& copy_config) { | 788 | const Tegra::Engines::Fermi2D::Config& copy_config) { |
| 720 | texture_cache.DoFermiCopy(src, dst, copy_config); | 789 | auto lock = texture_cache.AcquireLock(); |
| 790 | texture_cache.BlitImage(dst, src, copy_config); | ||
| 721 | return true; | 791 | return true; |
| 722 | } | 792 | } |
| 723 | 793 | ||
| @@ -727,20 +797,16 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 727 | return false; | 797 | return false; |
| 728 | } | 798 | } |
| 729 | 799 | ||
| 730 | const auto surface{texture_cache.TryFindFramebufferSurface(framebuffer_addr)}; | 800 | auto lock = texture_cache.AcquireLock(); |
| 731 | if (!surface) { | 801 | ImageView* const image_view = texture_cache.TryFindFramebufferImageView(framebuffer_addr); |
| 802 | if (!image_view) { | ||
| 732 | return false; | 803 | return false; |
| 733 | } | 804 | } |
| 734 | 805 | ||
| 735 | // Verify that the cached surface is the same size and format as the requested framebuffer | 806 | screen_info.image_view = image_view->Handle(VideoCommon::ImageViewType::e2D); |
| 736 | const auto& params{surface->GetSurfaceParams()}; | 807 | screen_info.width = image_view->size.width; |
| 737 | ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); | 808 | screen_info.height = image_view->size.height; |
| 738 | ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); | 809 | screen_info.is_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format); |
| 739 | |||
| 740 | screen_info.image = &surface->GetImage(); | ||
| 741 | screen_info.width = params.width; | ||
| 742 | screen_info.height = params.height; | ||
| 743 | screen_info.is_srgb = surface->GetSurfaceParams().srgb_conversion; | ||
| 744 | return true; | 810 | return true; |
| 745 | } | 811 | } |
| 746 | 812 | ||
| @@ -765,103 +831,6 @@ void RasterizerVulkan::FlushWork() { | |||
| 765 | draw_counter = 0; | 831 | draw_counter = 0; |
| 766 | } | 832 | } |
| 767 | 833 | ||
| 768 | RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments(bool is_clear) { | ||
| 769 | MICROPROFILE_SCOPE(Vulkan_RenderTargets); | ||
| 770 | |||
| 771 | const auto& regs = maxwell3d.regs; | ||
| 772 | auto& dirty = maxwell3d.dirty.flags; | ||
| 773 | const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets]; | ||
| 774 | dirty[VideoCommon::Dirty::RenderTargets] = false; | ||
| 775 | |||
| 776 | texture_cache.GuardRenderTargets(true); | ||
| 777 | |||
| 778 | Texceptions texceptions; | ||
| 779 | for (std::size_t rt = 0; rt < Maxwell::NumRenderTargets; ++rt) { | ||
| 780 | if (update_rendertargets) { | ||
| 781 | const bool preserve_contents = HasToPreserveColorContents(is_clear, regs); | ||
| 782 | color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, preserve_contents); | ||
| 783 | } | ||
| 784 | if (color_attachments[rt] && WalkAttachmentOverlaps(*color_attachments[rt])) { | ||
| 785 | texceptions[rt] = true; | ||
| 786 | } | ||
| 787 | } | ||
| 788 | |||
| 789 | if (update_rendertargets) { | ||
| 790 | const bool preserve_contents = HasToPreserveDepthContents(is_clear, regs); | ||
| 791 | zeta_attachment = texture_cache.GetDepthBufferSurface(preserve_contents); | ||
| 792 | } | ||
| 793 | if (zeta_attachment && WalkAttachmentOverlaps(*zeta_attachment)) { | ||
| 794 | texceptions[ZETA_TEXCEPTION_INDEX] = true; | ||
| 795 | } | ||
| 796 | |||
| 797 | texture_cache.GuardRenderTargets(false); | ||
| 798 | |||
| 799 | return texceptions; | ||
| 800 | } | ||
| 801 | |||
| 802 | bool RasterizerVulkan::WalkAttachmentOverlaps(const CachedSurfaceView& attachment) { | ||
| 803 | bool overlap = false; | ||
| 804 | for (auto& [view, layout] : sampled_views) { | ||
| 805 | if (!attachment.IsSameSurface(*view)) { | ||
| 806 | continue; | ||
| 807 | } | ||
| 808 | overlap = true; | ||
| 809 | *layout = VK_IMAGE_LAYOUT_GENERAL; | ||
| 810 | } | ||
| 811 | return overlap; | ||
| 812 | } | ||
| 813 | |||
| 814 | std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers( | ||
| 815 | VkRenderPass renderpass) { | ||
| 816 | FramebufferCacheKey key{ | ||
| 817 | .renderpass = renderpass, | ||
| 818 | .width = std::numeric_limits<u32>::max(), | ||
| 819 | .height = std::numeric_limits<u32>::max(), | ||
| 820 | .layers = std::numeric_limits<u32>::max(), | ||
| 821 | .views = {}, | ||
| 822 | }; | ||
| 823 | |||
| 824 | const auto try_push = [&key](const View& view) { | ||
| 825 | if (!view) { | ||
| 826 | return false; | ||
| 827 | } | ||
| 828 | key.views.push_back(view->GetAttachment()); | ||
| 829 | key.width = std::min(key.width, view->GetWidth()); | ||
| 830 | key.height = std::min(key.height, view->GetHeight()); | ||
| 831 | key.layers = std::min(key.layers, view->GetNumLayers()); | ||
| 832 | return true; | ||
| 833 | }; | ||
| 834 | |||
| 835 | const auto& regs = maxwell3d.regs; | ||
| 836 | const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count); | ||
| 837 | for (std::size_t index = 0; index < num_attachments; ++index) { | ||
| 838 | if (try_push(color_attachments[index])) { | ||
| 839 | texture_cache.MarkColorBufferInUse(index); | ||
| 840 | } | ||
| 841 | } | ||
| 842 | if (try_push(zeta_attachment)) { | ||
| 843 | texture_cache.MarkDepthBufferInUse(); | ||
| 844 | } | ||
| 845 | |||
| 846 | const auto [fbentry, is_cache_miss] = framebuffer_cache.try_emplace(key); | ||
| 847 | auto& framebuffer = fbentry->second; | ||
| 848 | if (is_cache_miss) { | ||
| 849 | framebuffer = device.GetLogical().CreateFramebuffer({ | ||
| 850 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | ||
| 851 | .pNext = nullptr, | ||
| 852 | .flags = 0, | ||
| 853 | .renderPass = key.renderpass, | ||
| 854 | .attachmentCount = static_cast<u32>(key.views.size()), | ||
| 855 | .pAttachments = key.views.data(), | ||
| 856 | .width = key.width, | ||
| 857 | .height = key.height, | ||
| 858 | .layers = key.layers, | ||
| 859 | }); | ||
| 860 | } | ||
| 861 | |||
| 862 | return {*framebuffer, VkExtent2D{key.width, key.height}}; | ||
| 863 | } | ||
| 864 | |||
| 865 | RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineState& fixed_state, | 834 | RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineState& fixed_state, |
| 866 | BufferBindings& buffer_bindings, | 835 | BufferBindings& buffer_bindings, |
| 867 | bool is_indexed, | 836 | bool is_indexed, |
| @@ -885,51 +854,37 @@ RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineSt | |||
| 885 | 854 | ||
| 886 | void RasterizerVulkan::SetupShaderDescriptors( | 855 | void RasterizerVulkan::SetupShaderDescriptors( |
| 887 | const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { | 856 | const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { |
| 888 | texture_cache.GuardSamplers(true); | 857 | image_view_indices.clear(); |
| 889 | 858 | sampler_handles.clear(); | |
| 890 | for (std::size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { | 859 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { |
| 891 | // Skip VertexA stage | ||
| 892 | Shader* const shader = shaders[stage + 1]; | 860 | Shader* const shader = shaders[stage + 1]; |
| 893 | if (!shader) { | 861 | if (!shader) { |
| 894 | continue; | 862 | continue; |
| 895 | } | 863 | } |
| 896 | const auto& entries = shader->GetEntries(); | 864 | const auto& entries = shader->GetEntries(); |
| 897 | SetupGraphicsConstBuffers(entries, stage); | ||
| 898 | SetupGraphicsGlobalBuffers(entries, stage); | ||
| 899 | SetupGraphicsUniformTexels(entries, stage); | 865 | SetupGraphicsUniformTexels(entries, stage); |
| 900 | SetupGraphicsTextures(entries, stage); | 866 | SetupGraphicsTextures(entries, stage); |
| 901 | SetupGraphicsStorageTexels(entries, stage); | 867 | SetupGraphicsStorageTexels(entries, stage); |
| 902 | SetupGraphicsImages(entries, stage); | 868 | SetupGraphicsImages(entries, stage); |
| 903 | } | 869 | } |
| 904 | texture_cache.GuardSamplers(false); | 870 | const std::span indices_span(image_view_indices.data(), image_view_indices.size()); |
| 905 | } | 871 | texture_cache.FillGraphicsImageViews(indices_span, image_view_ids); |
| 906 | 872 | ||
| 907 | void RasterizerVulkan::SetupImageTransitions( | 873 | update_descriptor_queue.Acquire(); |
| 908 | Texceptions texceptions, const std::array<View, Maxwell::NumRenderTargets>& color_attachments, | ||
| 909 | const View& zeta_attachment) { | ||
| 910 | TransitionImages(sampled_views, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT); | ||
| 911 | TransitionImages(image_views, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, | ||
| 912 | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); | ||
| 913 | 874 | ||
| 914 | for (std::size_t rt = 0; rt < std::size(color_attachments); ++rt) { | 875 | ImageViewId* image_view_id_ptr = image_view_ids.data(); |
| 915 | const auto color_attachment = color_attachments[rt]; | 876 | VkSampler* sampler_ptr = sampler_handles.data(); |
| 916 | if (color_attachment == nullptr) { | 877 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { |
| 878 | // Skip VertexA stage | ||
| 879 | Shader* const shader = shaders[stage + 1]; | ||
| 880 | if (!shader) { | ||
| 917 | continue; | 881 | continue; |
| 918 | } | 882 | } |
| 919 | const auto image_layout = | 883 | const auto& entries = shader->GetEntries(); |
| 920 | texceptions[rt] ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | 884 | SetupGraphicsConstBuffers(entries, stage); |
| 921 | color_attachment->Transition(image_layout, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | 885 | SetupGraphicsGlobalBuffers(entries, stage); |
| 922 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | | 886 | PushImageDescriptors(entries, texture_cache, update_descriptor_queue, image_view_id_ptr, |
| 923 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); | 887 | sampler_ptr); |
| 924 | } | ||
| 925 | |||
| 926 | if (zeta_attachment != nullptr) { | ||
| 927 | const auto image_layout = texceptions[ZETA_TEXCEPTION_INDEX] | ||
| 928 | ? VK_IMAGE_LAYOUT_GENERAL | ||
| 929 | : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; | ||
| 930 | zeta_attachment->Transition(image_layout, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, | ||
| 931 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 932 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); | ||
| 933 | } | 888 | } |
| 934 | } | 889 | } |
| 935 | 890 | ||
| @@ -948,7 +903,6 @@ void RasterizerVulkan::UpdateDynamicStates() { | |||
| 948 | UpdateDepthWriteEnable(regs); | 903 | UpdateDepthWriteEnable(regs); |
| 949 | UpdateDepthCompareOp(regs); | 904 | UpdateDepthCompareOp(regs); |
| 950 | UpdateFrontFace(regs); | 905 | UpdateFrontFace(regs); |
| 951 | UpdatePrimitiveTopology(regs); | ||
| 952 | UpdateStencilOp(regs); | 906 | UpdateStencilOp(regs); |
| 953 | UpdateStencilTestEnable(regs); | 907 | UpdateStencilTestEnable(regs); |
| 954 | } | 908 | } |
| @@ -1002,7 +956,7 @@ void RasterizerVulkan::EndTransformFeedback() { | |||
| 1002 | void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { | 956 | void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { |
| 1003 | const auto& regs = maxwell3d.regs; | 957 | const auto& regs = maxwell3d.regs; |
| 1004 | 958 | ||
| 1005 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 959 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 1006 | const auto& vertex_array = regs.vertex_array[index]; | 960 | const auto& vertex_array = regs.vertex_array[index]; |
| 1007 | if (!vertex_array.IsEnabled()) { | 961 | if (!vertex_array.IsEnabled()) { |
| 1008 | continue; | 962 | continue; |
| @@ -1011,7 +965,7 @@ void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { | |||
| 1011 | const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; | 965 | const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; |
| 1012 | 966 | ||
| 1013 | ASSERT(end >= start); | 967 | ASSERT(end >= start); |
| 1014 | const std::size_t size = end - start; | 968 | const size_t size = end - start; |
| 1015 | if (size == 0) { | 969 | if (size == 0) { |
| 1016 | buffer_bindings.AddVertexBinding(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE, 0); | 970 | buffer_bindings.AddVertexBinding(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE, 0); |
| 1017 | continue; | 971 | continue; |
| @@ -1072,7 +1026,7 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar | |||
| 1072 | } | 1026 | } |
| 1073 | } | 1027 | } |
| 1074 | 1028 | ||
| 1075 | void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage) { | 1029 | void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, size_t stage) { |
| 1076 | MICROPROFILE_SCOPE(Vulkan_ConstBuffers); | 1030 | MICROPROFILE_SCOPE(Vulkan_ConstBuffers); |
| 1077 | const auto& shader_stage = maxwell3d.state.shader_stages[stage]; | 1031 | const auto& shader_stage = maxwell3d.state.shader_stages[stage]; |
| 1078 | for (const auto& entry : entries.const_buffers) { | 1032 | for (const auto& entry : entries.const_buffers) { |
| @@ -1080,7 +1034,7 @@ void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, s | |||
| 1080 | } | 1034 | } |
| 1081 | } | 1035 | } |
| 1082 | 1036 | ||
| 1083 | void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage) { | 1037 | void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, size_t stage) { |
| 1084 | MICROPROFILE_SCOPE(Vulkan_GlobalBuffers); | 1038 | MICROPROFILE_SCOPE(Vulkan_GlobalBuffers); |
| 1085 | const auto& cbufs{maxwell3d.state.shader_stages[stage]}; | 1039 | const auto& cbufs{maxwell3d.state.shader_stages[stage]}; |
| 1086 | 1040 | ||
| @@ -1090,37 +1044,49 @@ void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, | |||
| 1090 | } | 1044 | } |
| 1091 | } | 1045 | } |
| 1092 | 1046 | ||
| 1093 | void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage) { | 1047 | void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, size_t stage) { |
| 1094 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1048 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1049 | const auto& regs = maxwell3d.regs; | ||
| 1050 | const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex; | ||
| 1095 | for (const auto& entry : entries.uniform_texels) { | 1051 | for (const auto& entry : entries.uniform_texels) { |
| 1096 | const auto image = GetTextureInfo(maxwell3d, entry, stage).tic; | 1052 | const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage); |
| 1097 | SetupUniformTexels(image, entry); | 1053 | image_view_indices.push_back(handle.image); |
| 1098 | } | 1054 | } |
| 1099 | } | 1055 | } |
| 1100 | 1056 | ||
| 1101 | void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage) { | 1057 | void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, size_t stage) { |
| 1102 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1058 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1059 | const auto& regs = maxwell3d.regs; | ||
| 1060 | const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex; | ||
| 1103 | for (const auto& entry : entries.samplers) { | 1061 | for (const auto& entry : entries.samplers) { |
| 1104 | for (std::size_t i = 0; i < entry.size; ++i) { | 1062 | for (size_t index = 0; index < entry.size; ++index) { |
| 1105 | const auto texture = GetTextureInfo(maxwell3d, entry, stage, i); | 1063 | const TextureHandle handle = |
| 1106 | SetupTexture(texture, entry); | 1064 | GetTextureInfo(maxwell3d, via_header_index, entry, stage, index); |
| 1065 | image_view_indices.push_back(handle.image); | ||
| 1066 | |||
| 1067 | Sampler* const sampler = texture_cache.GetGraphicsSampler(handle.sampler); | ||
| 1068 | sampler_handles.push_back(sampler->Handle()); | ||
| 1107 | } | 1069 | } |
| 1108 | } | 1070 | } |
| 1109 | } | 1071 | } |
| 1110 | 1072 | ||
| 1111 | void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage) { | 1073 | void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, size_t stage) { |
| 1112 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1074 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1075 | const auto& regs = maxwell3d.regs; | ||
| 1076 | const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex; | ||
| 1113 | for (const auto& entry : entries.storage_texels) { | 1077 | for (const auto& entry : entries.storage_texels) { |
| 1114 | const auto image = GetTextureInfo(maxwell3d, entry, stage).tic; | 1078 | const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage); |
| 1115 | SetupStorageTexel(image, entry); | 1079 | image_view_indices.push_back(handle.image); |
| 1116 | } | 1080 | } |
| 1117 | } | 1081 | } |
| 1118 | 1082 | ||
| 1119 | void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) { | 1083 | void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, size_t stage) { |
| 1120 | MICROPROFILE_SCOPE(Vulkan_Images); | 1084 | MICROPROFILE_SCOPE(Vulkan_Images); |
| 1085 | const auto& regs = maxwell3d.regs; | ||
| 1086 | const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex; | ||
| 1121 | for (const auto& entry : entries.images) { | 1087 | for (const auto& entry : entries.images) { |
| 1122 | const auto tic = GetTextureInfo(maxwell3d, entry, stage).tic; | 1088 | const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage); |
| 1123 | SetupImage(tic, entry); | 1089 | image_view_indices.push_back(handle.image); |
| 1124 | } | 1090 | } |
| 1125 | } | 1091 | } |
| 1126 | 1092 | ||
| @@ -1130,11 +1096,12 @@ void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) { | |||
| 1130 | for (const auto& entry : entries.const_buffers) { | 1096 | for (const auto& entry : entries.const_buffers) { |
| 1131 | const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; | 1097 | const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; |
| 1132 | const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value(); | 1098 | const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value(); |
| 1133 | Tegra::Engines::ConstBufferInfo buffer; | 1099 | const Tegra::Engines::ConstBufferInfo info{ |
| 1134 | buffer.address = config.Address(); | 1100 | .address = config.Address(), |
| 1135 | buffer.size = config.size; | 1101 | .size = config.size, |
| 1136 | buffer.enabled = mask[entry.GetIndex()]; | 1102 | .enabled = mask[entry.GetIndex()], |
| 1137 | SetupConstBuffer(entry, buffer); | 1103 | }; |
| 1104 | SetupConstBuffer(entry, info); | ||
| 1138 | } | 1105 | } |
| 1139 | } | 1106 | } |
| 1140 | 1107 | ||
| @@ -1149,35 +1116,46 @@ void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) { | |||
| 1149 | 1116 | ||
| 1150 | void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) { | 1117 | void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) { |
| 1151 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1118 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1119 | const bool via_header_index = kepler_compute.launch_description.linked_tsc; | ||
| 1152 | for (const auto& entry : entries.uniform_texels) { | 1120 | for (const auto& entry : entries.uniform_texels) { |
| 1153 | const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; | 1121 | const TextureHandle handle = |
| 1154 | SetupUniformTexels(image, entry); | 1122 | GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX); |
| 1123 | image_view_indices.push_back(handle.image); | ||
| 1155 | } | 1124 | } |
| 1156 | } | 1125 | } |
| 1157 | 1126 | ||
| 1158 | void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) { | 1127 | void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) { |
| 1159 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1128 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1129 | const bool via_header_index = kepler_compute.launch_description.linked_tsc; | ||
| 1160 | for (const auto& entry : entries.samplers) { | 1130 | for (const auto& entry : entries.samplers) { |
| 1161 | for (std::size_t i = 0; i < entry.size; ++i) { | 1131 | for (size_t index = 0; index < entry.size; ++index) { |
| 1162 | const auto texture = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex, i); | 1132 | const TextureHandle handle = GetTextureInfo(kepler_compute, via_header_index, entry, |
| 1163 | SetupTexture(texture, entry); | 1133 | COMPUTE_SHADER_INDEX, index); |
| 1134 | image_view_indices.push_back(handle.image); | ||
| 1135 | |||
| 1136 | Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler); | ||
| 1137 | sampler_handles.push_back(sampler->Handle()); | ||
| 1164 | } | 1138 | } |
| 1165 | } | 1139 | } |
| 1166 | } | 1140 | } |
| 1167 | 1141 | ||
| 1168 | void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) { | 1142 | void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) { |
| 1169 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1143 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1144 | const bool via_header_index = kepler_compute.launch_description.linked_tsc; | ||
| 1170 | for (const auto& entry : entries.storage_texels) { | 1145 | for (const auto& entry : entries.storage_texels) { |
| 1171 | const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; | 1146 | const TextureHandle handle = |
| 1172 | SetupStorageTexel(image, entry); | 1147 | GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX); |
| 1148 | image_view_indices.push_back(handle.image); | ||
| 1173 | } | 1149 | } |
| 1174 | } | 1150 | } |
| 1175 | 1151 | ||
| 1176 | void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { | 1152 | void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { |
| 1177 | MICROPROFILE_SCOPE(Vulkan_Images); | 1153 | MICROPROFILE_SCOPE(Vulkan_Images); |
| 1154 | const bool via_header_index = kepler_compute.launch_description.linked_tsc; | ||
| 1178 | for (const auto& entry : entries.images) { | 1155 | for (const auto& entry : entries.images) { |
| 1179 | const auto tic = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; | 1156 | const TextureHandle handle = |
| 1180 | SetupImage(tic, entry); | 1157 | GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX); |
| 1158 | image_view_indices.push_back(handle.image); | ||
| 1181 | } | 1159 | } |
| 1182 | } | 1160 | } |
| 1183 | 1161 | ||
| @@ -1188,14 +1166,12 @@ void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry, | |||
| 1188 | update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE); | 1166 | update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE); |
| 1189 | return; | 1167 | return; |
| 1190 | } | 1168 | } |
| 1191 | |||
| 1192 | // Align the size to avoid bad std140 interactions | 1169 | // Align the size to avoid bad std140 interactions |
| 1193 | const std::size_t size = | 1170 | const size_t size = Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float)); |
| 1194 | Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float)); | ||
| 1195 | ASSERT(size <= MaxConstbufferSize); | 1171 | ASSERT(size <= MaxConstbufferSize); |
| 1196 | 1172 | ||
| 1197 | const auto info = | 1173 | const u64 alignment = device.GetUniformBufferAlignment(); |
| 1198 | buffer_cache.UploadMemory(buffer.address, size, device.GetUniformBufferAlignment()); | 1174 | const auto info = buffer_cache.UploadMemory(buffer.address, size, alignment); |
| 1199 | update_descriptor_queue.AddBuffer(info.handle, info.offset, size); | 1175 | update_descriptor_queue.AddBuffer(info.handle, info.offset, size); |
| 1200 | } | 1176 | } |
| 1201 | 1177 | ||
| @@ -1208,7 +1184,7 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd | |||
| 1208 | // because Vulkan doesn't like empty buffers. | 1184 | // because Vulkan doesn't like empty buffers. |
| 1209 | // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the | 1185 | // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the |
| 1210 | // default buffer. | 1186 | // default buffer. |
| 1211 | static constexpr std::size_t dummy_size = 4; | 1187 | static constexpr size_t dummy_size = 4; |
| 1212 | const auto info = buffer_cache.GetEmptyBuffer(dummy_size); | 1188 | const auto info = buffer_cache.GetEmptyBuffer(dummy_size); |
| 1213 | update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size); | 1189 | update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size); |
| 1214 | return; | 1190 | return; |
| @@ -1219,55 +1195,6 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd | |||
| 1219 | update_descriptor_queue.AddBuffer(info.handle, info.offset, size); | 1195 | update_descriptor_queue.AddBuffer(info.handle, info.offset, size); |
| 1220 | } | 1196 | } |
| 1221 | 1197 | ||
| 1222 | void RasterizerVulkan::SetupUniformTexels(const Tegra::Texture::TICEntry& tic, | ||
| 1223 | const UniformTexelEntry& entry) { | ||
| 1224 | const auto view = texture_cache.GetTextureSurface(tic, entry); | ||
| 1225 | ASSERT(view->IsBufferView()); | ||
| 1226 | |||
| 1227 | update_descriptor_queue.AddTexelBuffer(view->GetBufferView()); | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | void RasterizerVulkan::SetupTexture(const Tegra::Texture::FullTextureInfo& texture, | ||
| 1231 | const SamplerEntry& entry) { | ||
| 1232 | auto view = texture_cache.GetTextureSurface(texture.tic, entry); | ||
| 1233 | ASSERT(!view->IsBufferView()); | ||
| 1234 | |||
| 1235 | const VkImageView image_view = view->GetImageView(texture.tic.x_source, texture.tic.y_source, | ||
| 1236 | texture.tic.z_source, texture.tic.w_source); | ||
| 1237 | const auto sampler = sampler_cache.GetSampler(texture.tsc); | ||
| 1238 | update_descriptor_queue.AddSampledImage(sampler, image_view); | ||
| 1239 | |||
| 1240 | VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout(); | ||
| 1241 | *image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; | ||
| 1242 | sampled_views.push_back(ImageView{std::move(view), image_layout}); | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | void RasterizerVulkan::SetupStorageTexel(const Tegra::Texture::TICEntry& tic, | ||
| 1246 | const StorageTexelEntry& entry) { | ||
| 1247 | const auto view = texture_cache.GetImageSurface(tic, entry); | ||
| 1248 | ASSERT(view->IsBufferView()); | ||
| 1249 | |||
| 1250 | update_descriptor_queue.AddTexelBuffer(view->GetBufferView()); | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry) { | ||
| 1254 | auto view = texture_cache.GetImageSurface(tic, entry); | ||
| 1255 | |||
| 1256 | if (entry.is_written) { | ||
| 1257 | view->MarkAsModified(texture_cache.Tick()); | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | UNIMPLEMENTED_IF(tic.IsBuffer()); | ||
| 1261 | |||
| 1262 | const VkImageView image_view = | ||
| 1263 | view->GetImageView(tic.x_source, tic.y_source, tic.z_source, tic.w_source); | ||
| 1264 | update_descriptor_queue.AddImage(image_view); | ||
| 1265 | |||
| 1266 | VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout(); | ||
| 1267 | *image_layout = VK_IMAGE_LAYOUT_GENERAL; | ||
| 1268 | image_views.push_back(ImageView{std::move(view), image_layout}); | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) { | 1198 | void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) { |
| 1272 | if (!state_tracker.TouchViewports()) { | 1199 | if (!state_tracker.TouchViewports()) { |
| 1273 | return; | 1200 | return; |
| @@ -1418,16 +1345,6 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) { | |||
| 1418 | [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); }); | 1345 | [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); }); |
| 1419 | } | 1346 | } |
| 1420 | 1347 | ||
| 1421 | void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) { | ||
| 1422 | const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value(); | ||
| 1423 | if (!state_tracker.ChangePrimitiveTopology(primitive_topology)) { | ||
| 1424 | return; | ||
| 1425 | } | ||
| 1426 | scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) { | ||
| 1427 | cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology)); | ||
| 1428 | }); | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) { | 1348 | void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) { |
| 1432 | if (!state_tracker.TouchStencilOp()) { | 1349 | if (!state_tracker.TouchStencilOp()) { |
| 1433 | return; | 1350 | return; |
| @@ -1469,8 +1386,8 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& | |||
| 1469 | }); | 1386 | }); |
| 1470 | } | 1387 | } |
| 1471 | 1388 | ||
| 1472 | std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const { | 1389 | size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const { |
| 1473 | std::size_t size = CalculateVertexArraysSize(); | 1390 | size_t size = CalculateVertexArraysSize(); |
| 1474 | if (is_indexed) { | 1391 | if (is_indexed) { |
| 1475 | size = Common::AlignUp(size, 4) + CalculateIndexBufferSize(); | 1392 | size = Common::AlignUp(size, 4) + CalculateIndexBufferSize(); |
| 1476 | } | 1393 | } |
| @@ -1478,15 +1395,15 @@ std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) | |||
| 1478 | return size; | 1395 | return size; |
| 1479 | } | 1396 | } |
| 1480 | 1397 | ||
| 1481 | std::size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const { | 1398 | size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const { |
| 1482 | return Tegra::Engines::KeplerCompute::NumConstBuffers * | 1399 | return Tegra::Engines::KeplerCompute::NumConstBuffers * |
| 1483 | (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment()); | 1400 | (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment()); |
| 1484 | } | 1401 | } |
| 1485 | 1402 | ||
| 1486 | std::size_t RasterizerVulkan::CalculateVertexArraysSize() const { | 1403 | size_t RasterizerVulkan::CalculateVertexArraysSize() const { |
| 1487 | const auto& regs = maxwell3d.regs; | 1404 | const auto& regs = maxwell3d.regs; |
| 1488 | 1405 | ||
| 1489 | std::size_t size = 0; | 1406 | size_t size = 0; |
| 1490 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { | 1407 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 1491 | // This implementation assumes that all attributes are used in the shader. | 1408 | // This implementation assumes that all attributes are used in the shader. |
| 1492 | const GPUVAddr start{regs.vertex_array[index].StartAddress()}; | 1409 | const GPUVAddr start{regs.vertex_array[index].StartAddress()}; |
| @@ -1498,12 +1415,12 @@ std::size_t RasterizerVulkan::CalculateVertexArraysSize() const { | |||
| 1498 | return size; | 1415 | return size; |
| 1499 | } | 1416 | } |
| 1500 | 1417 | ||
| 1501 | std::size_t RasterizerVulkan::CalculateIndexBufferSize() const { | 1418 | size_t RasterizerVulkan::CalculateIndexBufferSize() const { |
| 1502 | return static_cast<std::size_t>(maxwell3d.regs.index_array.count) * | 1419 | return static_cast<size_t>(maxwell3d.regs.index_array.count) * |
| 1503 | static_cast<std::size_t>(maxwell3d.regs.index_array.FormatSizeInBytes()); | 1420 | static_cast<size_t>(maxwell3d.regs.index_array.FormatSizeInBytes()); |
| 1504 | } | 1421 | } |
| 1505 | 1422 | ||
| 1506 | std::size_t RasterizerVulkan::CalculateConstBufferSize( | 1423 | size_t RasterizerVulkan::CalculateConstBufferSize( |
| 1507 | const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const { | 1424 | const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const { |
| 1508 | if (entry.IsIndirect()) { | 1425 | if (entry.IsIndirect()) { |
| 1509 | // Buffer is accessed indirectly, so upload the entire thing | 1426 | // Buffer is accessed indirectly, so upload the entire thing |
| @@ -1514,37 +1431,10 @@ std::size_t RasterizerVulkan::CalculateConstBufferSize( | |||
| 1514 | } | 1431 | } |
| 1515 | } | 1432 | } |
| 1516 | 1433 | ||
| 1517 | RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) const { | ||
| 1518 | const auto& regs = maxwell3d.regs; | ||
| 1519 | const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count); | ||
| 1520 | |||
| 1521 | RenderPassParams params; | ||
| 1522 | params.color_formats = {}; | ||
| 1523 | std::size_t color_texceptions = 0; | ||
| 1524 | |||
| 1525 | std::size_t index = 0; | ||
| 1526 | for (std::size_t rt = 0; rt < num_attachments; ++rt) { | ||
| 1527 | const auto& rendertarget = regs.rt[rt]; | ||
| 1528 | if (rendertarget.Address() == 0 || rendertarget.format == Tegra::RenderTargetFormat::NONE) { | ||
| 1529 | continue; | ||
| 1530 | } | ||
| 1531 | params.color_formats[index] = static_cast<u8>(rendertarget.format); | ||
| 1532 | color_texceptions |= (texceptions[rt] ? 1ULL : 0ULL) << index; | ||
| 1533 | ++index; | ||
| 1534 | } | ||
| 1535 | params.num_color_attachments = static_cast<u8>(index); | ||
| 1536 | params.texceptions = static_cast<u8>(color_texceptions); | ||
| 1537 | |||
| 1538 | params.zeta_format = regs.zeta_enable ? static_cast<u8>(regs.zeta.format) : 0; | ||
| 1539 | params.zeta_texception = texceptions[ZETA_TEXCEPTION_INDEX]; | ||
| 1540 | return params; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | VkBuffer RasterizerVulkan::DefaultBuffer() { | 1434 | VkBuffer RasterizerVulkan::DefaultBuffer() { |
| 1544 | if (default_buffer) { | 1435 | if (default_buffer) { |
| 1545 | return *default_buffer; | 1436 | return *default_buffer; |
| 1546 | } | 1437 | } |
| 1547 | |||
| 1548 | default_buffer = device.GetLogical().CreateBuffer({ | 1438 | default_buffer = device.GetLogical().CreateBuffer({ |
| 1549 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 1439 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 1550 | .pNext = nullptr, | 1440 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index b47c8fc13..4695718e9 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -11,11 +11,11 @@ | |||
| 11 | #include <vector> | 11 | #include <vector> |
| 12 | 12 | ||
| 13 | #include <boost/container/static_vector.hpp> | 13 | #include <boost/container/static_vector.hpp> |
| 14 | #include <boost/functional/hash.hpp> | ||
| 15 | 14 | ||
| 16 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 17 | #include "video_core/rasterizer_accelerated.h" | 16 | #include "video_core/rasterizer_accelerated.h" |
| 18 | #include "video_core/rasterizer_interface.h" | 17 | #include "video_core/rasterizer_interface.h" |
| 18 | #include "video_core/renderer_vulkan/blit_image.h" | ||
| 19 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 19 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 20 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 20 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 21 | #include "video_core/renderer_vulkan/vk_compute_pass.h" | 21 | #include "video_core/renderer_vulkan/vk_compute_pass.h" |
| @@ -24,14 +24,13 @@ | |||
| 24 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 24 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 25 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 25 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 26 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 26 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 27 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||
| 28 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" | ||
| 29 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 30 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 28 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 29 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" | ||
| 31 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 30 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 32 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 31 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 33 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 34 | #include "video_core/shader/async_shaders.h" | 32 | #include "video_core/shader/async_shaders.h" |
| 33 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 35 | 34 | ||
| 36 | namespace Core { | 35 | namespace Core { |
| 37 | class System; | 36 | class System; |
| @@ -49,67 +48,16 @@ namespace Vulkan { | |||
| 49 | 48 | ||
| 50 | struct VKScreenInfo; | 49 | struct VKScreenInfo; |
| 51 | 50 | ||
| 52 | using ImageViewsPack = boost::container::static_vector<VkImageView, Maxwell::NumRenderTargets + 1>; | ||
| 53 | |||
| 54 | struct FramebufferCacheKey { | ||
| 55 | VkRenderPass renderpass{}; | ||
| 56 | u32 width = 0; | ||
| 57 | u32 height = 0; | ||
| 58 | u32 layers = 0; | ||
| 59 | ImageViewsPack views; | ||
| 60 | |||
| 61 | std::size_t Hash() const noexcept { | ||
| 62 | std::size_t hash = 0; | ||
| 63 | boost::hash_combine(hash, static_cast<VkRenderPass>(renderpass)); | ||
| 64 | for (const auto& view : views) { | ||
| 65 | boost::hash_combine(hash, static_cast<VkImageView>(view)); | ||
| 66 | } | ||
| 67 | boost::hash_combine(hash, width); | ||
| 68 | boost::hash_combine(hash, height); | ||
| 69 | boost::hash_combine(hash, layers); | ||
| 70 | return hash; | ||
| 71 | } | ||
| 72 | |||
| 73 | bool operator==(const FramebufferCacheKey& rhs) const noexcept { | ||
| 74 | return std::tie(renderpass, views, width, height, layers) == | ||
| 75 | std::tie(rhs.renderpass, rhs.views, rhs.width, rhs.height, rhs.layers); | ||
| 76 | } | ||
| 77 | |||
| 78 | bool operator!=(const FramebufferCacheKey& rhs) const noexcept { | ||
| 79 | return !operator==(rhs); | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | |||
| 83 | } // namespace Vulkan | ||
| 84 | |||
| 85 | namespace std { | ||
| 86 | |||
| 87 | template <> | ||
| 88 | struct hash<Vulkan::FramebufferCacheKey> { | ||
| 89 | std::size_t operator()(const Vulkan::FramebufferCacheKey& k) const noexcept { | ||
| 90 | return k.Hash(); | ||
| 91 | } | ||
| 92 | }; | ||
| 93 | |||
| 94 | } // namespace std | ||
| 95 | |||
| 96 | namespace Vulkan { | ||
| 97 | |||
| 98 | class StateTracker; | 51 | class StateTracker; |
| 99 | class BufferBindings; | 52 | class BufferBindings; |
| 100 | 53 | ||
| 101 | struct ImageView { | ||
| 102 | View view; | ||
| 103 | VkImageLayout* layout = nullptr; | ||
| 104 | }; | ||
| 105 | |||
| 106 | class RasterizerVulkan final : public VideoCore::RasterizerAccelerated { | 54 | class RasterizerVulkan final : public VideoCore::RasterizerAccelerated { |
| 107 | public: | 55 | public: |
| 108 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu, | 56 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 109 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, | 57 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, |
| 110 | VKScreenInfo& screen_info, const VKDevice& device, | 58 | VKScreenInfo& screen_info_, const Device& device_, |
| 111 | VKMemoryManager& memory_manager, StateTracker& state_tracker, | 59 | VKMemoryManager& memory_manager_, StateTracker& state_tracker_, |
| 112 | VKScheduler& scheduler); | 60 | VKScheduler& scheduler_); |
| 113 | ~RasterizerVulkan() override; | 61 | ~RasterizerVulkan() override; |
| 114 | 62 | ||
| 115 | void Draw(bool is_indexed, bool is_instanced) override; | 63 | void Draw(bool is_indexed, bool is_instanced) override; |
| @@ -123,15 +71,18 @@ public: | |||
| 123 | void InvalidateRegion(VAddr addr, u64 size) override; | 71 | void InvalidateRegion(VAddr addr, u64 size) override; |
| 124 | void OnCPUWrite(VAddr addr, u64 size) override; | 72 | void OnCPUWrite(VAddr addr, u64 size) override; |
| 125 | void SyncGuestHost() override; | 73 | void SyncGuestHost() override; |
| 74 | void UnmapMemory(VAddr addr, u64 size) override; | ||
| 126 | void SignalSemaphore(GPUVAddr addr, u32 value) override; | 75 | void SignalSemaphore(GPUVAddr addr, u32 value) override; |
| 127 | void SignalSyncPoint(u32 value) override; | 76 | void SignalSyncPoint(u32 value) override; |
| 128 | void ReleaseFences() override; | 77 | void ReleaseFences() override; |
| 129 | void FlushAndInvalidateRegion(VAddr addr, u64 size) override; | 78 | void FlushAndInvalidateRegion(VAddr addr, u64 size) override; |
| 130 | void WaitForIdle() override; | 79 | void WaitForIdle() override; |
| 80 | void FragmentBarrier() override; | ||
| 81 | void TiledCacheBarrier() override; | ||
| 131 | void FlushCommands() override; | 82 | void FlushCommands() override; |
| 132 | void TickFrame() override; | 83 | void TickFrame() override; |
| 133 | bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, | 84 | bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, |
| 134 | const Tegra::Engines::Fermi2D::Regs::Surface& dst, | 85 | const Tegra::Engines::Fermi2D::Surface& dst, |
| 135 | const Tegra::Engines::Fermi2D::Config& copy_config) override; | 86 | const Tegra::Engines::Fermi2D::Config& copy_config) override; |
| 136 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, | 87 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, |
| 137 | u32 pixel_stride) override; | 88 | u32 pixel_stride) override; |
| @@ -145,11 +96,17 @@ public: | |||
| 145 | } | 96 | } |
| 146 | 97 | ||
| 147 | /// Maximum supported size that a constbuffer can have in bytes. | 98 | /// Maximum supported size that a constbuffer can have in bytes. |
| 148 | static constexpr std::size_t MaxConstbufferSize = 0x10000; | 99 | static constexpr size_t MaxConstbufferSize = 0x10000; |
| 149 | static_assert(MaxConstbufferSize % (4 * sizeof(float)) == 0, | 100 | static_assert(MaxConstbufferSize % (4 * sizeof(float)) == 0, |
| 150 | "The maximum size of a constbuffer must be a multiple of the size of GLvec4"); | 101 | "The maximum size of a constbuffer must be a multiple of the size of GLvec4"); |
| 151 | 102 | ||
| 152 | private: | 103 | private: |
| 104 | static constexpr size_t MAX_TEXTURES = 192; | ||
| 105 | static constexpr size_t MAX_IMAGES = 48; | ||
| 106 | static constexpr size_t MAX_IMAGE_VIEWS = MAX_TEXTURES + MAX_IMAGES; | ||
| 107 | |||
| 108 | static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float); | ||
| 109 | |||
| 153 | struct DrawParameters { | 110 | struct DrawParameters { |
| 154 | void Draw(vk::CommandBuffer cmdbuf) const; | 111 | void Draw(vk::CommandBuffer cmdbuf) const; |
| 155 | 112 | ||
| @@ -160,20 +117,8 @@ private: | |||
| 160 | bool is_indexed = 0; | 117 | bool is_indexed = 0; |
| 161 | }; | 118 | }; |
| 162 | 119 | ||
| 163 | using Texceptions = std::bitset<Maxwell::NumRenderTargets + 1>; | ||
| 164 | |||
| 165 | static constexpr std::size_t ZETA_TEXCEPTION_INDEX = 8; | ||
| 166 | static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float); | ||
| 167 | |||
| 168 | void FlushWork(); | 120 | void FlushWork(); |
| 169 | 121 | ||
| 170 | /// @brief Updates the currently bound attachments | ||
| 171 | /// @param is_clear True when the framebuffer is updated as a clear | ||
| 172 | /// @return Bitfield of attachments being used as sampled textures | ||
| 173 | Texceptions UpdateAttachments(bool is_clear); | ||
| 174 | |||
| 175 | std::tuple<VkFramebuffer, VkExtent2D> ConfigureFramebuffers(VkRenderPass renderpass); | ||
| 176 | |||
| 177 | /// Setups geometry buffers and state. | 122 | /// Setups geometry buffers and state. |
| 178 | DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings, | 123 | DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings, |
| 179 | bool is_indexed, bool is_instanced); | 124 | bool is_indexed, bool is_instanced); |
| @@ -181,18 +126,12 @@ private: | |||
| 181 | /// Setup descriptors in the graphics pipeline. | 126 | /// Setup descriptors in the graphics pipeline. |
| 182 | void SetupShaderDescriptors(const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders); | 127 | void SetupShaderDescriptors(const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders); |
| 183 | 128 | ||
| 184 | void SetupImageTransitions(Texceptions texceptions, | ||
| 185 | const std::array<View, Maxwell::NumRenderTargets>& color_attachments, | ||
| 186 | const View& zeta_attachment); | ||
| 187 | |||
| 188 | void UpdateDynamicStates(); | 129 | void UpdateDynamicStates(); |
| 189 | 130 | ||
| 190 | void BeginTransformFeedback(); | 131 | void BeginTransformFeedback(); |
| 191 | 132 | ||
| 192 | void EndTransformFeedback(); | 133 | void EndTransformFeedback(); |
| 193 | 134 | ||
| 194 | bool WalkAttachmentOverlaps(const CachedSurfaceView& attachment); | ||
| 195 | |||
| 196 | void SetupVertexArrays(BufferBindings& buffer_bindings); | 135 | void SetupVertexArrays(BufferBindings& buffer_bindings); |
| 197 | 136 | ||
| 198 | void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed); | 137 | void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed); |
| @@ -238,14 +177,6 @@ private: | |||
| 238 | 177 | ||
| 239 | void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address); | 178 | void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address); |
| 240 | 179 | ||
| 241 | void SetupUniformTexels(const Tegra::Texture::TICEntry& image, const UniformTexelEntry& entry); | ||
| 242 | |||
| 243 | void SetupTexture(const Tegra::Texture::FullTextureInfo& texture, const SamplerEntry& entry); | ||
| 244 | |||
| 245 | void SetupStorageTexel(const Tegra::Texture::TICEntry& tic, const StorageTexelEntry& entry); | ||
| 246 | |||
| 247 | void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry); | ||
| 248 | |||
| 249 | void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs); | 180 | void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs); |
| 250 | void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs); | 181 | void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs); |
| 251 | void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs); | 182 | void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs); |
| @@ -259,22 +190,19 @@ private: | |||
| 259 | void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); | 190 | void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); |
| 260 | void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs); | 191 | void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs); |
| 261 | void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); | 192 | void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); |
| 262 | void UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs); | ||
| 263 | void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); | 193 | void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); |
| 264 | void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); | 194 | void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); |
| 265 | 195 | ||
| 266 | std::size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const; | 196 | size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const; |
| 267 | |||
| 268 | std::size_t CalculateComputeStreamBufferSize() const; | ||
| 269 | 197 | ||
| 270 | std::size_t CalculateVertexArraysSize() const; | 198 | size_t CalculateComputeStreamBufferSize() const; |
| 271 | 199 | ||
| 272 | std::size_t CalculateIndexBufferSize() const; | 200 | size_t CalculateVertexArraysSize() const; |
| 273 | 201 | ||
| 274 | std::size_t CalculateConstBufferSize(const ConstBufferEntry& entry, | 202 | size_t CalculateIndexBufferSize() const; |
| 275 | const Tegra::Engines::ConstBufferInfo& buffer) const; | ||
| 276 | 203 | ||
| 277 | RenderPassParams GetRenderPassParams(Texceptions texceptions) const; | 204 | size_t CalculateConstBufferSize(const ConstBufferEntry& entry, |
| 205 | const Tegra::Engines::ConstBufferInfo& buffer) const; | ||
| 278 | 206 | ||
| 279 | VkBuffer DefaultBuffer(); | 207 | VkBuffer DefaultBuffer(); |
| 280 | 208 | ||
| @@ -284,23 +212,24 @@ private: | |||
| 284 | Tegra::Engines::KeplerCompute& kepler_compute; | 212 | Tegra::Engines::KeplerCompute& kepler_compute; |
| 285 | 213 | ||
| 286 | VKScreenInfo& screen_info; | 214 | VKScreenInfo& screen_info; |
| 287 | const VKDevice& device; | 215 | const Device& device; |
| 288 | VKMemoryManager& memory_manager; | 216 | VKMemoryManager& memory_manager; |
| 289 | StateTracker& state_tracker; | 217 | StateTracker& state_tracker; |
| 290 | VKScheduler& scheduler; | 218 | VKScheduler& scheduler; |
| 291 | 219 | ||
| 220 | VKStreamBuffer stream_buffer; | ||
| 292 | VKStagingBufferPool staging_pool; | 221 | VKStagingBufferPool staging_pool; |
| 293 | VKDescriptorPool descriptor_pool; | 222 | VKDescriptorPool descriptor_pool; |
| 294 | VKUpdateDescriptorQueue update_descriptor_queue; | 223 | VKUpdateDescriptorQueue update_descriptor_queue; |
| 295 | VKRenderPassCache renderpass_cache; | 224 | BlitImageHelper blit_image; |
| 296 | QuadArrayPass quad_array_pass; | 225 | QuadArrayPass quad_array_pass; |
| 297 | QuadIndexedPass quad_indexed_pass; | 226 | QuadIndexedPass quad_indexed_pass; |
| 298 | Uint8Pass uint8_pass; | 227 | Uint8Pass uint8_pass; |
| 299 | 228 | ||
| 300 | VKTextureCache texture_cache; | 229 | TextureCacheRuntime texture_cache_runtime; |
| 230 | TextureCache texture_cache; | ||
| 301 | VKPipelineCache pipeline_cache; | 231 | VKPipelineCache pipeline_cache; |
| 302 | VKBufferCache buffer_cache; | 232 | VKBufferCache buffer_cache; |
| 303 | VKSamplerCache sampler_cache; | ||
| 304 | VKQueryCache query_cache; | 233 | VKQueryCache query_cache; |
| 305 | VKFenceManager fence_manager; | 234 | VKFenceManager fence_manager; |
| 306 | 235 | ||
| @@ -309,16 +238,11 @@ private: | |||
| 309 | vk::Event wfi_event; | 238 | vk::Event wfi_event; |
| 310 | VideoCommon::Shader::AsyncShaders async_shaders; | 239 | VideoCommon::Shader::AsyncShaders async_shaders; |
| 311 | 240 | ||
| 312 | std::array<View, Maxwell::NumRenderTargets> color_attachments; | 241 | boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices; |
| 313 | View zeta_attachment; | 242 | std::array<VideoCommon::ImageViewId, MAX_IMAGE_VIEWS> image_view_ids; |
| 314 | 243 | boost::container::static_vector<VkSampler, MAX_TEXTURES> sampler_handles; | |
| 315 | std::vector<ImageView> sampled_views; | ||
| 316 | std::vector<ImageView> image_views; | ||
| 317 | 244 | ||
| 318 | u32 draw_counter = 0; | 245 | u32 draw_counter = 0; |
| 319 | |||
| 320 | // TODO(Rodrigo): Invalidate on image destruction | ||
| 321 | std::unordered_map<FramebufferCacheKey, vk::Framebuffer> framebuffer_cache; | ||
| 322 | }; | 246 | }; |
| 323 | 247 | ||
| 324 | } // namespace Vulkan | 248 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp deleted file mode 100644 index 80284cf92..000000000 --- a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp +++ /dev/null | |||
| @@ -1,158 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include <memory> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/cityhash.h" | ||
| 10 | #include "video_core/engines/maxwell_3d.h" | ||
| 11 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | ||
| 12 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 13 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 15 | |||
| 16 | namespace Vulkan { | ||
| 17 | |||
| 18 | std::size_t RenderPassParams::Hash() const noexcept { | ||
| 19 | const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this); | ||
| 20 | return static_cast<std::size_t>(hash); | ||
| 21 | } | ||
| 22 | |||
| 23 | bool RenderPassParams::operator==(const RenderPassParams& rhs) const noexcept { | ||
| 24 | return std::memcmp(&rhs, this, sizeof *this) == 0; | ||
| 25 | } | ||
| 26 | |||
| 27 | VKRenderPassCache::VKRenderPassCache(const VKDevice& device) : device{device} {} | ||
| 28 | |||
| 29 | VKRenderPassCache::~VKRenderPassCache() = default; | ||
| 30 | |||
| 31 | VkRenderPass VKRenderPassCache::GetRenderPass(const RenderPassParams& params) { | ||
| 32 | const auto [pair, is_cache_miss] = cache.try_emplace(params); | ||
| 33 | auto& entry = pair->second; | ||
| 34 | if (is_cache_miss) { | ||
| 35 | entry = CreateRenderPass(params); | ||
| 36 | } | ||
| 37 | return *entry; | ||
| 38 | } | ||
| 39 | |||
| 40 | vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& params) const { | ||
| 41 | using namespace VideoCore::Surface; | ||
| 42 | const std::size_t num_attachments = static_cast<std::size_t>(params.num_color_attachments); | ||
| 43 | |||
| 44 | std::vector<VkAttachmentDescription> descriptors; | ||
| 45 | descriptors.reserve(num_attachments); | ||
| 46 | |||
| 47 | std::vector<VkAttachmentReference> color_references; | ||
| 48 | color_references.reserve(num_attachments); | ||
| 49 | |||
| 50 | for (std::size_t rt = 0; rt < num_attachments; ++rt) { | ||
| 51 | const auto guest_format = static_cast<Tegra::RenderTargetFormat>(params.color_formats[rt]); | ||
| 52 | const PixelFormat pixel_format = PixelFormatFromRenderTargetFormat(guest_format); | ||
| 53 | const auto format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format); | ||
| 54 | ASSERT_MSG(format.attachable, "Trying to attach a non-attachable format with format={}", | ||
| 55 | static_cast<int>(pixel_format)); | ||
| 56 | |||
| 57 | // TODO(Rodrigo): Add MAY_ALIAS_BIT when it's needed. | ||
| 58 | const VkImageLayout color_layout = ((params.texceptions >> rt) & 1) != 0 | ||
| 59 | ? VK_IMAGE_LAYOUT_GENERAL | ||
| 60 | : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | ||
| 61 | descriptors.push_back({ | ||
| 62 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, | ||
| 63 | .format = format.format, | ||
| 64 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 65 | .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 66 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 67 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, | ||
| 68 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, | ||
| 69 | .initialLayout = color_layout, | ||
| 70 | .finalLayout = color_layout, | ||
| 71 | }); | ||
| 72 | |||
| 73 | color_references.push_back({ | ||
| 74 | .attachment = static_cast<u32>(rt), | ||
| 75 | .layout = color_layout, | ||
| 76 | }); | ||
| 77 | } | ||
| 78 | |||
| 79 | VkAttachmentReference zeta_attachment_ref; | ||
| 80 | const bool has_zeta = params.zeta_format != 0; | ||
| 81 | if (has_zeta) { | ||
| 82 | const auto guest_format = static_cast<Tegra::DepthFormat>(params.zeta_format); | ||
| 83 | const PixelFormat pixel_format = PixelFormatFromDepthFormat(guest_format); | ||
| 84 | const auto format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format); | ||
| 85 | ASSERT_MSG(format.attachable, "Trying to attach a non-attachable format with format={}", | ||
| 86 | static_cast<int>(pixel_format)); | ||
| 87 | |||
| 88 | const VkImageLayout zeta_layout = params.zeta_texception != 0 | ||
| 89 | ? VK_IMAGE_LAYOUT_GENERAL | ||
| 90 | : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; | ||
| 91 | descriptors.push_back({ | ||
| 92 | .flags = 0, | ||
| 93 | .format = format.format, | ||
| 94 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 95 | .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 96 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 97 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 98 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 99 | .initialLayout = zeta_layout, | ||
| 100 | .finalLayout = zeta_layout, | ||
| 101 | }); | ||
| 102 | |||
| 103 | zeta_attachment_ref = { | ||
| 104 | .attachment = static_cast<u32>(num_attachments), | ||
| 105 | .layout = zeta_layout, | ||
| 106 | }; | ||
| 107 | } | ||
| 108 | |||
| 109 | const VkSubpassDescription subpass_description{ | ||
| 110 | .flags = 0, | ||
| 111 | .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 112 | .inputAttachmentCount = 0, | ||
| 113 | .pInputAttachments = nullptr, | ||
| 114 | .colorAttachmentCount = static_cast<u32>(color_references.size()), | ||
| 115 | .pColorAttachments = color_references.data(), | ||
| 116 | .pResolveAttachments = nullptr, | ||
| 117 | .pDepthStencilAttachment = has_zeta ? &zeta_attachment_ref : nullptr, | ||
| 118 | .preserveAttachmentCount = 0, | ||
| 119 | .pPreserveAttachments = nullptr, | ||
| 120 | }; | ||
| 121 | |||
| 122 | VkAccessFlags access = 0; | ||
| 123 | VkPipelineStageFlags stage = 0; | ||
| 124 | if (!color_references.empty()) { | ||
| 125 | access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | ||
| 126 | stage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | ||
| 127 | } | ||
| 128 | |||
| 129 | if (has_zeta) { | ||
| 130 | access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 131 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; | ||
| 132 | stage |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; | ||
| 133 | } | ||
| 134 | |||
| 135 | const VkSubpassDependency subpass_dependency{ | ||
| 136 | .srcSubpass = VK_SUBPASS_EXTERNAL, | ||
| 137 | .dstSubpass = 0, | ||
| 138 | .srcStageMask = stage, | ||
| 139 | .dstStageMask = stage, | ||
| 140 | .srcAccessMask = 0, | ||
| 141 | .dstAccessMask = access, | ||
| 142 | .dependencyFlags = 0, | ||
| 143 | }; | ||
| 144 | |||
| 145 | return device.GetLogical().CreateRenderPass({ | ||
| 146 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | ||
| 147 | .pNext = nullptr, | ||
| 148 | .flags = 0, | ||
| 149 | .attachmentCount = static_cast<u32>(descriptors.size()), | ||
| 150 | .pAttachments = descriptors.data(), | ||
| 151 | .subpassCount = 1, | ||
| 152 | .pSubpasses = &subpass_description, | ||
| 153 | .dependencyCount = 1, | ||
| 154 | .pDependencies = &subpass_dependency, | ||
| 155 | }); | ||
| 156 | } | ||
| 157 | |||
| 158 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.h b/src/video_core/renderer_vulkan/vk_renderpass_cache.h deleted file mode 100644 index 8b0fec720..000000000 --- a/src/video_core/renderer_vulkan/vk_renderpass_cache.h +++ /dev/null | |||
| @@ -1,70 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <type_traits> | ||
| 8 | #include <unordered_map> | ||
| 9 | |||
| 10 | #include <boost/container/static_vector.hpp> | ||
| 11 | #include <boost/functional/hash.hpp> | ||
| 12 | |||
| 13 | #include "video_core/engines/maxwell_3d.h" | ||
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 15 | #include "video_core/surface.h" | ||
| 16 | |||
| 17 | namespace Vulkan { | ||
| 18 | |||
| 19 | class VKDevice; | ||
| 20 | |||
| 21 | struct RenderPassParams { | ||
| 22 | std::array<u8, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> color_formats; | ||
| 23 | u8 num_color_attachments; | ||
| 24 | u8 texceptions; | ||
| 25 | |||
| 26 | u8 zeta_format; | ||
| 27 | u8 zeta_texception; | ||
| 28 | |||
| 29 | std::size_t Hash() const noexcept; | ||
| 30 | |||
| 31 | bool operator==(const RenderPassParams& rhs) const noexcept; | ||
| 32 | |||
| 33 | bool operator!=(const RenderPassParams& rhs) const noexcept { | ||
| 34 | return !operator==(rhs); | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | static_assert(std::has_unique_object_representations_v<RenderPassParams>); | ||
| 38 | static_assert(std::is_trivially_copyable_v<RenderPassParams>); | ||
| 39 | static_assert(std::is_trivially_constructible_v<RenderPassParams>); | ||
| 40 | |||
| 41 | } // namespace Vulkan | ||
| 42 | |||
| 43 | namespace std { | ||
| 44 | |||
| 45 | template <> | ||
| 46 | struct hash<Vulkan::RenderPassParams> { | ||
| 47 | std::size_t operator()(const Vulkan::RenderPassParams& k) const noexcept { | ||
| 48 | return k.Hash(); | ||
| 49 | } | ||
| 50 | }; | ||
| 51 | |||
| 52 | } // namespace std | ||
| 53 | |||
| 54 | namespace Vulkan { | ||
| 55 | |||
| 56 | class VKRenderPassCache final { | ||
| 57 | public: | ||
| 58 | explicit VKRenderPassCache(const VKDevice& device); | ||
| 59 | ~VKRenderPassCache(); | ||
| 60 | |||
| 61 | VkRenderPass GetRenderPass(const RenderPassParams& params); | ||
| 62 | |||
| 63 | private: | ||
| 64 | vk::RenderPass CreateRenderPass(const RenderPassParams& params) const; | ||
| 65 | |||
| 66 | const VKDevice& device; | ||
| 67 | std::unordered_map<RenderPassParams, vk::RenderPass> cache; | ||
| 68 | }; | ||
| 69 | |||
| 70 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp deleted file mode 100644 index b068888f9..000000000 --- a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp +++ /dev/null | |||
| @@ -1,83 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <unordered_map> | ||
| 6 | |||
| 7 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | ||
| 8 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" | ||
| 9 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 10 | #include "video_core/textures/texture.h" | ||
| 11 | |||
| 12 | using Tegra::Texture::TextureMipmapFilter; | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | namespace { | ||
| 17 | |||
| 18 | VkBorderColor ConvertBorderColor(std::array<float, 4> color) { | ||
| 19 | // TODO(Rodrigo): Manage integer border colors | ||
| 20 | if (color == std::array<float, 4>{0, 0, 0, 0}) { | ||
| 21 | return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; | ||
| 22 | } else if (color == std::array<float, 4>{0, 0, 0, 1}) { | ||
| 23 | return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; | ||
| 24 | } else if (color == std::array<float, 4>{1, 1, 1, 1}) { | ||
| 25 | return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; | ||
| 26 | } | ||
| 27 | if (color[0] + color[1] + color[2] > 1.35f) { | ||
| 28 | // If color elements are brighter than roughly 0.5 average, use white border | ||
| 29 | return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; | ||
| 30 | } else if (color[3] > 0.5f) { | ||
| 31 | return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; | ||
| 32 | } else { | ||
| 33 | return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | } // Anonymous namespace | ||
| 38 | |||
| 39 | VKSamplerCache::VKSamplerCache(const VKDevice& device) : device{device} {} | ||
| 40 | |||
| 41 | VKSamplerCache::~VKSamplerCache() = default; | ||
| 42 | |||
| 43 | vk::Sampler VKSamplerCache::CreateSampler(const Tegra::Texture::TSCEntry& tsc) const { | ||
| 44 | const bool arbitrary_borders = device.IsExtCustomBorderColorSupported(); | ||
| 45 | const std::array color = tsc.GetBorderColor(); | ||
| 46 | |||
| 47 | VkSamplerCustomBorderColorCreateInfoEXT border{ | ||
| 48 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT, | ||
| 49 | .pNext = nullptr, | ||
| 50 | .customBorderColor = {}, | ||
| 51 | .format = VK_FORMAT_UNDEFINED, | ||
| 52 | }; | ||
| 53 | std::memcpy(&border.customBorderColor, color.data(), sizeof(color)); | ||
| 54 | |||
| 55 | return device.GetLogical().CreateSampler({ | ||
| 56 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 57 | .pNext = arbitrary_borders ? &border : nullptr, | ||
| 58 | .flags = 0, | ||
| 59 | .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter), | ||
| 60 | .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter), | ||
| 61 | .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter), | ||
| 62 | .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter), | ||
| 63 | .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter), | ||
| 64 | .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter), | ||
| 65 | .mipLodBias = tsc.GetLodBias(), | ||
| 66 | .anisotropyEnable = | ||
| 67 | static_cast<VkBool32>(tsc.GetMaxAnisotropy() > 1.0f ? VK_TRUE : VK_FALSE), | ||
| 68 | .maxAnisotropy = tsc.GetMaxAnisotropy(), | ||
| 69 | .compareEnable = tsc.depth_compare_enabled, | ||
| 70 | .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), | ||
| 71 | .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.GetMinLod(), | ||
| 72 | .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.GetMaxLod(), | ||
| 73 | .borderColor = | ||
| 74 | arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color), | ||
| 75 | .unnormalizedCoordinates = VK_FALSE, | ||
| 76 | }); | ||
| 77 | } | ||
| 78 | |||
| 79 | VkSampler VKSamplerCache::ToSamplerType(const vk::Sampler& sampler) const { | ||
| 80 | return *sampler; | ||
| 81 | } | ||
| 82 | |||
| 83 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.h b/src/video_core/renderer_vulkan/vk_sampler_cache.h deleted file mode 100644 index a33d1c0ee..000000000 --- a/src/video_core/renderer_vulkan/vk_sampler_cache.h +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 8 | #include "video_core/sampler_cache.h" | ||
| 9 | #include "video_core/textures/texture.h" | ||
| 10 | |||
| 11 | namespace Vulkan { | ||
| 12 | |||
| 13 | class VKDevice; | ||
| 14 | |||
| 15 | class VKSamplerCache final : public VideoCommon::SamplerCache<VkSampler, vk::Sampler> { | ||
| 16 | public: | ||
| 17 | explicit VKSamplerCache(const VKDevice& device); | ||
| 18 | ~VKSamplerCache(); | ||
| 19 | |||
| 20 | protected: | ||
| 21 | vk::Sampler CreateSampler(const Tegra::Texture::TSCEntry& tsc) const override; | ||
| 22 | |||
| 23 | VkSampler ToSamplerType(const vk::Sampler& sampler) const override; | ||
| 24 | |||
| 25 | private: | ||
| 26 | const VKDevice& device; | ||
| 27 | }; | ||
| 28 | |||
| 29 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 1a483dc71..66004f9c0 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp | |||
| @@ -11,12 +11,13 @@ | |||
| 11 | #include "common/microprofile.h" | 11 | #include "common/microprofile.h" |
| 12 | #include "common/thread.h" | 12 | #include "common/thread.h" |
| 13 | #include "video_core/renderer_vulkan/vk_command_pool.h" | 13 | #include "video_core/renderer_vulkan/vk_command_pool.h" |
| 14 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 14 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 16 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 15 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 17 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 16 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 18 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 17 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 19 | #include "video_core/renderer_vulkan/wrapper.h" | 18 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 19 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 20 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 20 | 21 | ||
| 21 | namespace Vulkan { | 22 | namespace Vulkan { |
| 22 | 23 | ||
| @@ -36,7 +37,7 @@ void VKScheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf) { | |||
| 36 | last = nullptr; | 37 | last = nullptr; |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | VKScheduler::VKScheduler(const VKDevice& device_, StateTracker& state_tracker_) | 40 | VKScheduler::VKScheduler(const Device& device_, StateTracker& state_tracker_) |
| 40 | : device{device_}, state_tracker{state_tracker_}, | 41 | : device{device_}, state_tracker{state_tracker_}, |
| 41 | master_semaphore{std::make_unique<MasterSemaphore>(device)}, | 42 | master_semaphore{std::make_unique<MasterSemaphore>(device)}, |
| 42 | command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} { | 43 | command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} { |
| @@ -96,38 +97,39 @@ void VKScheduler::DispatchWork() { | |||
| 96 | AcquireNewChunk(); | 97 | AcquireNewChunk(); |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | void VKScheduler::RequestRenderpass(VkRenderPass renderpass, VkFramebuffer framebuffer, | 100 | void VKScheduler::RequestRenderpass(const Framebuffer* framebuffer) { |
| 100 | VkExtent2D render_area) { | 101 | const VkRenderPass renderpass = framebuffer->RenderPass(); |
| 101 | if (renderpass == state.renderpass && framebuffer == state.framebuffer && | 102 | const VkFramebuffer framebuffer_handle = framebuffer->Handle(); |
| 103 | const VkExtent2D render_area = framebuffer->RenderArea(); | ||
| 104 | if (renderpass == state.renderpass && framebuffer_handle == state.framebuffer && | ||
| 102 | render_area.width == state.render_area.width && | 105 | render_area.width == state.render_area.width && |
| 103 | render_area.height == state.render_area.height) { | 106 | render_area.height == state.render_area.height) { |
| 104 | return; | 107 | return; |
| 105 | } | 108 | } |
| 106 | const bool end_renderpass = state.renderpass != nullptr; | 109 | EndRenderPass(); |
| 107 | state.renderpass = renderpass; | 110 | state.renderpass = renderpass; |
| 108 | state.framebuffer = framebuffer; | 111 | state.framebuffer = framebuffer_handle; |
| 109 | state.render_area = render_area; | 112 | state.render_area = render_area; |
| 110 | 113 | ||
| 111 | const VkRenderPassBeginInfo renderpass_bi{ | 114 | Record([renderpass, framebuffer_handle, render_area](vk::CommandBuffer cmdbuf) { |
| 112 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | 115 | const VkRenderPassBeginInfo renderpass_bi{ |
| 113 | .pNext = nullptr, | 116 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, |
| 114 | .renderPass = renderpass, | 117 | .pNext = nullptr, |
| 115 | .framebuffer = framebuffer, | 118 | .renderPass = renderpass, |
| 116 | .renderArea = | 119 | .framebuffer = framebuffer_handle, |
| 117 | { | 120 | .renderArea = |
| 118 | .offset = {.x = 0, .y = 0}, | 121 | { |
| 119 | .extent = render_area, | 122 | .offset = {.x = 0, .y = 0}, |
| 120 | }, | 123 | .extent = render_area, |
| 121 | .clearValueCount = 0, | 124 | }, |
| 122 | .pClearValues = nullptr, | 125 | .clearValueCount = 0, |
| 123 | }; | 126 | .pClearValues = nullptr, |
| 124 | 127 | }; | |
| 125 | Record([renderpass_bi, end_renderpass](vk::CommandBuffer cmdbuf) { | ||
| 126 | if (end_renderpass) { | ||
| 127 | cmdbuf.EndRenderPass(); | ||
| 128 | } | ||
| 129 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | 128 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); |
| 130 | }); | 129 | }); |
| 130 | num_renderpass_images = framebuffer->NumImages(); | ||
| 131 | renderpass_images = framebuffer->Images(); | ||
| 132 | renderpass_image_ranges = framebuffer->ImageRanges(); | ||
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | void VKScheduler::RequestOutsideRenderPassOperationContext() { | 135 | void VKScheduler::RequestOutsideRenderPassOperationContext() { |
| @@ -241,8 +243,37 @@ void VKScheduler::EndRenderPass() { | |||
| 241 | if (!state.renderpass) { | 243 | if (!state.renderpass) { |
| 242 | return; | 244 | return; |
| 243 | } | 245 | } |
| 246 | Record([num_images = num_renderpass_images, images = renderpass_images, | ||
| 247 | ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) { | ||
| 248 | std::array<VkImageMemoryBarrier, 9> barriers; | ||
| 249 | for (size_t i = 0; i < num_images; ++i) { | ||
| 250 | barriers[i] = VkImageMemoryBarrier{ | ||
| 251 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 252 | .pNext = nullptr, | ||
| 253 | .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 254 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, | ||
| 255 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | | ||
| 256 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | | ||
| 257 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 258 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 259 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, | ||
| 260 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 261 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 262 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 263 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 264 | .image = images[i], | ||
| 265 | .subresourceRange = ranges[i], | ||
| 266 | }; | ||
| 267 | } | ||
| 268 | cmdbuf.EndRenderPass(); | ||
| 269 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | | ||
| 270 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | | ||
| 271 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 272 | VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, nullptr, | ||
| 273 | vk::Span(barriers.data(), num_images)); | ||
| 274 | }); | ||
| 244 | state.renderpass = nullptr; | 275 | state.renderpass = nullptr; |
| 245 | Record([](vk::CommandBuffer cmdbuf) { cmdbuf.EndRenderPass(); }); | 276 | num_renderpass_images = 0; |
| 246 | } | 277 | } |
| 247 | 278 | ||
| 248 | void VKScheduler::AcquireNewChunk() { | 279 | void VKScheduler::AcquireNewChunk() { |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 7be8a19f0..4cd43e425 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h | |||
| @@ -12,21 +12,22 @@ | |||
| 12 | #include <utility> | 12 | #include <utility> |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/threadsafe_queue.h" | 14 | #include "common/threadsafe_queue.h" |
| 15 | #include "video_core/renderer_vulkan/wrapper.h" | 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 16 | 16 | ||
| 17 | namespace Vulkan { | 17 | namespace Vulkan { |
| 18 | 18 | ||
| 19 | class CommandPool; | 19 | class CommandPool; |
| 20 | class Device; | ||
| 21 | class Framebuffer; | ||
| 20 | class MasterSemaphore; | 22 | class MasterSemaphore; |
| 21 | class StateTracker; | 23 | class StateTracker; |
| 22 | class VKDevice; | ||
| 23 | class VKQueryCache; | 24 | class VKQueryCache; |
| 24 | 25 | ||
| 25 | /// The scheduler abstracts command buffer and fence management with an interface that's able to do | 26 | /// The scheduler abstracts command buffer and fence management with an interface that's able to do |
| 26 | /// OpenGL-like operations on Vulkan command buffers. | 27 | /// OpenGL-like operations on Vulkan command buffers. |
| 27 | class VKScheduler { | 28 | class VKScheduler { |
| 28 | public: | 29 | public: |
| 29 | explicit VKScheduler(const VKDevice& device, StateTracker& state_tracker); | 30 | explicit VKScheduler(const Device& device, StateTracker& state_tracker); |
| 30 | ~VKScheduler(); | 31 | ~VKScheduler(); |
| 31 | 32 | ||
| 32 | /// Returns the current command buffer tick. | 33 | /// Returns the current command buffer tick. |
| @@ -52,8 +53,7 @@ public: | |||
| 52 | void DispatchWork(); | 53 | void DispatchWork(); |
| 53 | 54 | ||
| 54 | /// Requests to begin a renderpass. | 55 | /// Requests to begin a renderpass. |
| 55 | void RequestRenderpass(VkRenderPass renderpass, VkFramebuffer framebuffer, | 56 | void RequestRenderpass(const Framebuffer* framebuffer); |
| 56 | VkExtent2D render_area); | ||
| 57 | 57 | ||
| 58 | /// Requests the current executino context to be able to execute operations only allowed outside | 58 | /// Requests the current executino context to be able to execute operations only allowed outside |
| 59 | /// of a renderpass. | 59 | /// of a renderpass. |
| @@ -62,6 +62,9 @@ public: | |||
| 62 | /// Binds a pipeline to the current execution context. | 62 | /// Binds a pipeline to the current execution context. |
| 63 | void BindGraphicsPipeline(VkPipeline pipeline); | 63 | void BindGraphicsPipeline(VkPipeline pipeline); |
| 64 | 64 | ||
| 65 | /// Invalidates current command buffer state except for render passes | ||
| 66 | void InvalidateState(); | ||
| 67 | |||
| 65 | /// Assigns the query cache. | 68 | /// Assigns the query cache. |
| 66 | void SetQueryCache(VKQueryCache& query_cache_) { | 69 | void SetQueryCache(VKQueryCache& query_cache_) { |
| 67 | query_cache = &query_cache_; | 70 | query_cache = &query_cache_; |
| @@ -104,7 +107,7 @@ private: | |||
| 104 | template <typename T> | 107 | template <typename T> |
| 105 | class TypedCommand final : public Command { | 108 | class TypedCommand final : public Command { |
| 106 | public: | 109 | public: |
| 107 | explicit TypedCommand(T&& command) : command{std::move(command)} {} | 110 | explicit TypedCommand(T&& command_) : command{std::move(command_)} {} |
| 108 | ~TypedCommand() override = default; | 111 | ~TypedCommand() override = default; |
| 109 | 112 | ||
| 110 | TypedCommand(TypedCommand&&) = delete; | 113 | TypedCommand(TypedCommand&&) = delete; |
| @@ -170,15 +173,13 @@ private: | |||
| 170 | 173 | ||
| 171 | void AllocateNewContext(); | 174 | void AllocateNewContext(); |
| 172 | 175 | ||
| 173 | void InvalidateState(); | ||
| 174 | |||
| 175 | void EndPendingOperations(); | 176 | void EndPendingOperations(); |
| 176 | 177 | ||
| 177 | void EndRenderPass(); | 178 | void EndRenderPass(); |
| 178 | 179 | ||
| 179 | void AcquireNewChunk(); | 180 | void AcquireNewChunk(); |
| 180 | 181 | ||
| 181 | const VKDevice& device; | 182 | const Device& device; |
| 182 | StateTracker& state_tracker; | 183 | StateTracker& state_tracker; |
| 183 | 184 | ||
| 184 | std::unique_ptr<MasterSemaphore> master_semaphore; | 185 | std::unique_ptr<MasterSemaphore> master_semaphore; |
| @@ -192,6 +193,11 @@ private: | |||
| 192 | std::thread worker_thread; | 193 | std::thread worker_thread; |
| 193 | 194 | ||
| 194 | State state; | 195 | State state; |
| 196 | |||
| 197 | u32 num_renderpass_images = 0; | ||
| 198 | std::array<VkImage, 9> renderpass_images{}; | ||
| 199 | std::array<VkImageSubresourceRange, 9> renderpass_image_ranges{}; | ||
| 200 | |||
| 195 | Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_queue; | 201 | Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_queue; |
| 196 | Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_reserve; | 202 | Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_reserve; |
| 197 | std::mutex mutex; | 203 | std::mutex mutex; |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index cd7d7a4e4..89cbe01ad 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -22,11 +22,11 @@ | |||
| 22 | #include "video_core/engines/shader_bytecode.h" | 22 | #include "video_core/engines/shader_bytecode.h" |
| 23 | #include "video_core/engines/shader_header.h" | 23 | #include "video_core/engines/shader_header.h" |
| 24 | #include "video_core/engines/shader_type.h" | 24 | #include "video_core/engines/shader_type.h" |
| 25 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 26 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | 25 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" |
| 27 | #include "video_core/shader/node.h" | 26 | #include "video_core/shader/node.h" |
| 28 | #include "video_core/shader/shader_ir.h" | 27 | #include "video_core/shader/shader_ir.h" |
| 29 | #include "video_core/shader/transform_feedback.h" | 28 | #include "video_core/shader/transform_feedback.h" |
| 29 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 30 | 30 | ||
| 31 | namespace Vulkan { | 31 | namespace Vulkan { |
| 32 | 32 | ||
| @@ -55,8 +55,8 @@ enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat }; | |||
| 55 | 55 | ||
| 56 | class Expression final { | 56 | class Expression final { |
| 57 | public: | 57 | public: |
| 58 | Expression(Id id, Type type) : id{id}, type{type} { | 58 | Expression(Id id_, Type type_) : id{id_}, type{type_} { |
| 59 | ASSERT(type != Type::Void); | 59 | ASSERT(type_ != Type::Void); |
| 60 | } | 60 | } |
| 61 | Expression() : type{Type::Void} {} | 61 | Expression() : type{Type::Void} {} |
| 62 | 62 | ||
| @@ -102,7 +102,7 @@ struct GenericVaryingDescription { | |||
| 102 | bool is_scalar = false; | 102 | bool is_scalar = false; |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | spv::Dim GetSamplerDim(const Sampler& sampler) { | 105 | spv::Dim GetSamplerDim(const SamplerEntry& sampler) { |
| 106 | ASSERT(!sampler.is_buffer); | 106 | ASSERT(!sampler.is_buffer); |
| 107 | switch (sampler.type) { | 107 | switch (sampler.type) { |
| 108 | case Tegra::Shader::TextureType::Texture1D: | 108 | case Tegra::Shader::TextureType::Texture1D: |
| @@ -114,12 +114,12 @@ spv::Dim GetSamplerDim(const Sampler& sampler) { | |||
| 114 | case Tegra::Shader::TextureType::TextureCube: | 114 | case Tegra::Shader::TextureType::TextureCube: |
| 115 | return spv::Dim::Cube; | 115 | return spv::Dim::Cube; |
| 116 | default: | 116 | default: |
| 117 | UNIMPLEMENTED_MSG("Unimplemented sampler type={}", static_cast<int>(sampler.type)); | 117 | UNIMPLEMENTED_MSG("Unimplemented sampler type={}", sampler.type); |
| 118 | return spv::Dim::Dim2D; | 118 | return spv::Dim::Dim2D; |
| 119 | } | 119 | } |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | std::pair<spv::Dim, bool> GetImageDim(const Image& image) { | 122 | std::pair<spv::Dim, bool> GetImageDim(const ImageEntry& image) { |
| 123 | switch (image.type) { | 123 | switch (image.type) { |
| 124 | case Tegra::Shader::ImageType::Texture1D: | 124 | case Tegra::Shader::ImageType::Texture1D: |
| 125 | return {spv::Dim::Dim1D, false}; | 125 | return {spv::Dim::Dim1D, false}; |
| @@ -134,7 +134,7 @@ std::pair<spv::Dim, bool> GetImageDim(const Image& image) { | |||
| 134 | case Tegra::Shader::ImageType::Texture3D: | 134 | case Tegra::Shader::ImageType::Texture3D: |
| 135 | return {spv::Dim::Dim3D, false}; | 135 | return {spv::Dim::Dim3D, false}; |
| 136 | default: | 136 | default: |
| 137 | UNIMPLEMENTED_MSG("Unimplemented image type={}", static_cast<int>(image.type)); | 137 | UNIMPLEMENTED_MSG("Unimplemented image type={}", image.type); |
| 138 | return {spv::Dim::Dim2D, false}; | 138 | return {spv::Dim::Dim2D, false}; |
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| @@ -274,12 +274,12 @@ bool IsPrecise(Operation operand) { | |||
| 274 | 274 | ||
| 275 | class SPIRVDecompiler final : public Sirit::Module { | 275 | class SPIRVDecompiler final : public Sirit::Module { |
| 276 | public: | 276 | public: |
| 277 | explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage, | 277 | explicit SPIRVDecompiler(const Device& device_, const ShaderIR& ir_, ShaderType stage_, |
| 278 | const Registry& registry, const Specialization& specialization) | 278 | const Registry& registry_, const Specialization& specialization_) |
| 279 | : Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()}, | 279 | : Module(0x00010300), device{device_}, ir{ir_}, stage{stage_}, header{ir_.GetHeader()}, |
| 280 | registry{registry}, specialization{specialization} { | 280 | registry{registry_}, specialization{specialization_} { |
| 281 | if (stage != ShaderType::Compute) { | 281 | if (stage_ != ShaderType::Compute) { |
| 282 | transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo()); | 282 | transform_feedback = BuildTransformFeedback(registry_.GetGraphicsInfo()); |
| 283 | } | 283 | } |
| 284 | 284 | ||
| 285 | AddCapability(spv::Capability::Shader); | 285 | AddCapability(spv::Capability::Shader); |
| @@ -293,6 +293,7 @@ public: | |||
| 293 | AddCapability(spv::Capability::DrawParameters); | 293 | AddCapability(spv::Capability::DrawParameters); |
| 294 | AddCapability(spv::Capability::SubgroupBallotKHR); | 294 | AddCapability(spv::Capability::SubgroupBallotKHR); |
| 295 | AddCapability(spv::Capability::SubgroupVoteKHR); | 295 | AddCapability(spv::Capability::SubgroupVoteKHR); |
| 296 | AddExtension("SPV_KHR_16bit_storage"); | ||
| 296 | AddExtension("SPV_KHR_shader_ballot"); | 297 | AddExtension("SPV_KHR_shader_ballot"); |
| 297 | AddExtension("SPV_KHR_subgroup_vote"); | 298 | AddExtension("SPV_KHR_subgroup_vote"); |
| 298 | AddExtension("SPV_KHR_storage_buffer_storage_class"); | 299 | AddExtension("SPV_KHR_storage_buffer_storage_class"); |
| @@ -307,7 +308,6 @@ public: | |||
| 307 | "supported on this device"); | 308 | "supported on this device"); |
| 308 | } | 309 | } |
| 309 | } | 310 | } |
| 310 | |||
| 311 | if (ir.UsesLayer() || ir.UsesViewportIndex()) { | 311 | if (ir.UsesLayer() || ir.UsesViewportIndex()) { |
| 312 | if (ir.UsesViewportIndex()) { | 312 | if (ir.UsesViewportIndex()) { |
| 313 | AddCapability(spv::Capability::MultiViewport); | 313 | AddCapability(spv::Capability::MultiViewport); |
| @@ -317,15 +317,13 @@ public: | |||
| 317 | AddCapability(spv::Capability::ShaderViewportIndexLayerEXT); | 317 | AddCapability(spv::Capability::ShaderViewportIndexLayerEXT); |
| 318 | } | 318 | } |
| 319 | } | 319 | } |
| 320 | |||
| 321 | if (device.IsFormatlessImageLoadSupported()) { | 320 | if (device.IsFormatlessImageLoadSupported()) { |
| 322 | AddCapability(spv::Capability::StorageImageReadWithoutFormat); | 321 | AddCapability(spv::Capability::StorageImageReadWithoutFormat); |
| 323 | } | 322 | } |
| 324 | |||
| 325 | if (device.IsFloat16Supported()) { | 323 | if (device.IsFloat16Supported()) { |
| 326 | AddCapability(spv::Capability::Float16); | 324 | AddCapability(spv::Capability::Float16); |
| 327 | } | 325 | } |
| 328 | t_scalar_half = Name(TypeFloat(device.IsFloat16Supported() ? 16 : 32), "scalar_half"); | 326 | t_scalar_half = Name(TypeFloat(device_.IsFloat16Supported() ? 16 : 32), "scalar_half"); |
| 329 | t_half = Name(TypeVector(t_scalar_half, 2), "half"); | 327 | t_half = Name(TypeVector(t_scalar_half, 2), "half"); |
| 330 | 328 | ||
| 331 | const Id main = Decompile(); | 329 | const Id main = Decompile(); |
| @@ -369,6 +367,9 @@ public: | |||
| 369 | if (header.ps.omap.depth) { | 367 | if (header.ps.omap.depth) { |
| 370 | AddExecutionMode(main, spv::ExecutionMode::DepthReplacing); | 368 | AddExecutionMode(main, spv::ExecutionMode::DepthReplacing); |
| 371 | } | 369 | } |
| 370 | if (specialization.early_fragment_tests) { | ||
| 371 | AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests); | ||
| 372 | } | ||
| 372 | break; | 373 | break; |
| 373 | case ShaderType::Compute: | 374 | case ShaderType::Compute: |
| 374 | const auto workgroup_size = specialization.workgroup_size; | 375 | const auto workgroup_size = specialization.workgroup_size; |
| @@ -972,7 +973,7 @@ private: | |||
| 972 | return binding; | 973 | return binding; |
| 973 | } | 974 | } |
| 974 | 975 | ||
| 975 | void DeclareImage(const Image& image, u32& binding) { | 976 | void DeclareImage(const ImageEntry& image, u32& binding) { |
| 976 | const auto [dim, arrayed] = GetImageDim(image); | 977 | const auto [dim, arrayed] = GetImageDim(image); |
| 977 | constexpr int depth = 0; | 978 | constexpr int depth = 0; |
| 978 | constexpr bool ms = false; | 979 | constexpr bool ms = false; |
| @@ -1080,9 +1081,9 @@ private: | |||
| 1080 | indices.point_size = AddBuiltIn(t_float, spv::BuiltIn::PointSize, "point_size"); | 1081 | indices.point_size = AddBuiltIn(t_float, spv::BuiltIn::PointSize, "point_size"); |
| 1081 | } | 1082 | } |
| 1082 | 1083 | ||
| 1083 | const auto& output_attributes = ir.GetOutputAttributes(); | 1084 | const auto& ir_output_attributes = ir.GetOutputAttributes(); |
| 1084 | const bool declare_clip_distances = | 1085 | const bool declare_clip_distances = std::any_of( |
| 1085 | std::any_of(output_attributes.begin(), output_attributes.end(), [](const auto& index) { | 1086 | ir_output_attributes.begin(), ir_output_attributes.end(), [](const auto& index) { |
| 1086 | return index == Attribute::Index::ClipDistances0123 || | 1087 | return index == Attribute::Index::ClipDistances0123 || |
| 1087 | index == Attribute::Index::ClipDistances4567; | 1088 | index == Attribute::Index::ClipDistances4567; |
| 1088 | }); | 1089 | }); |
| @@ -1246,7 +1247,7 @@ private: | |||
| 1246 | const Id pointer = ArrayPass(type_descriptor.scalar, attribute_id, elements); | 1247 | const Id pointer = ArrayPass(type_descriptor.scalar, attribute_id, elements); |
| 1247 | return {OpLoad(GetTypeDefinition(type), pointer), type}; | 1248 | return {OpLoad(GetTypeDefinition(type), pointer), type}; |
| 1248 | } | 1249 | } |
| 1249 | UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); | 1250 | UNIMPLEMENTED_MSG("Unhandled input attribute: {}", attribute); |
| 1250 | return {v_float_zero, Type::Float}; | 1251 | return {v_float_zero, Type::Float}; |
| 1251 | } | 1252 | } |
| 1252 | 1253 | ||
| @@ -1882,7 +1883,7 @@ private: | |||
| 1882 | case Tegra::Shader::TextureType::Texture3D: | 1883 | case Tegra::Shader::TextureType::Texture3D: |
| 1883 | return 3; | 1884 | return 3; |
| 1884 | default: | 1885 | default: |
| 1885 | UNREACHABLE_MSG("Invalid texture type={}", static_cast<int>(type)); | 1886 | UNREACHABLE_MSG("Invalid texture type={}", type); |
| 1886 | return 2; | 1887 | return 2; |
| 1887 | } | 1888 | } |
| 1888 | }(); | 1889 | }(); |
| @@ -2067,6 +2068,46 @@ private: | |||
| 2067 | return {}; | 2068 | return {}; |
| 2068 | } | 2069 | } |
| 2069 | 2070 | ||
| 2071 | Id MaxwellToSpirvComparison(Maxwell::ComparisonOp compare_op, Id operand_1, Id operand_2) { | ||
| 2072 | using Compare = Maxwell::ComparisonOp; | ||
| 2073 | switch (compare_op) { | ||
| 2074 | case Compare::NeverOld: | ||
| 2075 | return v_false; // Never let the test pass | ||
| 2076 | case Compare::LessOld: | ||
| 2077 | return OpFOrdLessThan(t_bool, operand_1, operand_2); | ||
| 2078 | case Compare::EqualOld: | ||
| 2079 | return OpFOrdEqual(t_bool, operand_1, operand_2); | ||
| 2080 | case Compare::LessEqualOld: | ||
| 2081 | return OpFOrdLessThanEqual(t_bool, operand_1, operand_2); | ||
| 2082 | case Compare::GreaterOld: | ||
| 2083 | return OpFOrdGreaterThan(t_bool, operand_1, operand_2); | ||
| 2084 | case Compare::NotEqualOld: | ||
| 2085 | return OpFOrdNotEqual(t_bool, operand_1, operand_2); | ||
| 2086 | case Compare::GreaterEqualOld: | ||
| 2087 | return OpFOrdGreaterThanEqual(t_bool, operand_1, operand_2); | ||
| 2088 | default: | ||
| 2089 | UNREACHABLE(); | ||
| 2090 | return v_true; | ||
| 2091 | } | ||
| 2092 | } | ||
| 2093 | |||
| 2094 | void AlphaTest(Id pointer) { | ||
| 2095 | if (specialization.alpha_test_func == Maxwell::ComparisonOp::AlwaysOld) { | ||
| 2096 | return; | ||
| 2097 | } | ||
| 2098 | const Id true_label = OpLabel(); | ||
| 2099 | const Id discard_label = OpLabel(); | ||
| 2100 | const Id alpha_reference = Constant(t_float, specialization.alpha_test_ref); | ||
| 2101 | const Id alpha_value = OpLoad(t_float, pointer); | ||
| 2102 | const Id condition = | ||
| 2103 | MaxwellToSpirvComparison(specialization.alpha_test_func, alpha_value, alpha_reference); | ||
| 2104 | |||
| 2105 | OpBranchConditional(condition, true_label, discard_label); | ||
| 2106 | AddLabel(discard_label); | ||
| 2107 | OpKill(); | ||
| 2108 | AddLabel(true_label); | ||
| 2109 | } | ||
| 2110 | |||
| 2070 | void PreExit() { | 2111 | void PreExit() { |
| 2071 | if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { | 2112 | if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { |
| 2072 | const u32 position_index = out_indices.position.value(); | 2113 | const u32 position_index = out_indices.position.value(); |
| @@ -2078,8 +2119,7 @@ private: | |||
| 2078 | OpStore(z_pointer, depth); | 2119 | OpStore(z_pointer, depth); |
| 2079 | } | 2120 | } |
| 2080 | if (stage == ShaderType::Fragment) { | 2121 | if (stage == ShaderType::Fragment) { |
| 2081 | const auto SafeGetRegister = [&](u32 reg) { | 2122 | const auto SafeGetRegister = [this](u32 reg) { |
| 2082 | // TODO(Rodrigo): Replace with contains once C++20 releases | ||
| 2083 | if (const auto it = registers.find(reg); it != registers.end()) { | 2123 | if (const auto it = registers.find(reg); it != registers.end()) { |
| 2084 | return OpLoad(t_float, it->second); | 2124 | return OpLoad(t_float, it->second); |
| 2085 | } | 2125 | } |
| @@ -2089,8 +2129,6 @@ private: | |||
| 2089 | UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, | 2129 | UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, |
| 2090 | "Sample mask write is unimplemented"); | 2130 | "Sample mask write is unimplemented"); |
| 2091 | 2131 | ||
| 2092 | // TODO(Rodrigo): Alpha testing | ||
| 2093 | |||
| 2094 | // Write the color outputs using the data in the shader registers, disabled | 2132 | // Write the color outputs using the data in the shader registers, disabled |
| 2095 | // rendertargets/components are skipped in the register assignment. | 2133 | // rendertargets/components are skipped in the register assignment. |
| 2096 | u32 current_reg = 0; | 2134 | u32 current_reg = 0; |
| @@ -2102,6 +2140,9 @@ private: | |||
| 2102 | } | 2140 | } |
| 2103 | const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); | 2141 | const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); |
| 2104 | OpStore(pointer, SafeGetRegister(current_reg)); | 2142 | OpStore(pointer, SafeGetRegister(current_reg)); |
| 2143 | if (rt == 0 && component == 3) { | ||
| 2144 | AlphaTest(pointer); | ||
| 2145 | } | ||
| 2105 | ++current_reg; | 2146 | ++current_reg; |
| 2106 | } | 2147 | } |
| 2107 | } | 2148 | } |
| @@ -2701,7 +2742,7 @@ private: | |||
| 2701 | }; | 2742 | }; |
| 2702 | static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount)); | 2743 | static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount)); |
| 2703 | 2744 | ||
| 2704 | const VKDevice& device; | 2745 | const Device& device; |
| 2705 | const ShaderIR& ir; | 2746 | const ShaderIR& ir; |
| 2706 | const ShaderType stage; | 2747 | const ShaderType stage; |
| 2707 | const Tegra::Shader::Header header; | 2748 | const Tegra::Shader::Header header; |
| @@ -2843,7 +2884,7 @@ private: | |||
| 2843 | 2884 | ||
| 2844 | class ExprDecompiler { | 2885 | class ExprDecompiler { |
| 2845 | public: | 2886 | public: |
| 2846 | explicit ExprDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} | 2887 | explicit ExprDecompiler(SPIRVDecompiler& decomp_) : decomp{decomp_} {} |
| 2847 | 2888 | ||
| 2848 | Id operator()(const ExprAnd& expr) { | 2889 | Id operator()(const ExprAnd& expr) { |
| 2849 | const Id type_def = decomp.GetTypeDefinition(Type::Bool); | 2890 | const Id type_def = decomp.GetTypeDefinition(Type::Bool); |
| @@ -2899,7 +2940,7 @@ private: | |||
| 2899 | 2940 | ||
| 2900 | class ASTDecompiler { | 2941 | class ASTDecompiler { |
| 2901 | public: | 2942 | public: |
| 2902 | explicit ASTDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} | 2943 | explicit ASTDecompiler(SPIRVDecompiler& decomp_) : decomp{decomp_} {} |
| 2903 | 2944 | ||
| 2904 | void operator()(const ASTProgram& ast) { | 2945 | void operator()(const ASTProgram& ast) { |
| 2905 | ASTNode current = ast.nodes.GetFirst(); | 2946 | ASTNode current = ast.nodes.GetFirst(); |
| @@ -3089,7 +3130,7 @@ ShaderEntries GenerateShaderEntries(const VideoCommon::Shader::ShaderIR& ir) { | |||
| 3089 | return entries; | 3130 | return entries; |
| 3090 | } | 3131 | } |
| 3091 | 3132 | ||
| 3092 | std::vector<u32> Decompile(const VKDevice& device, const VideoCommon::Shader::ShaderIR& ir, | 3133 | std::vector<u32> Decompile(const Device& device, const VideoCommon::Shader::ShaderIR& ir, |
| 3093 | ShaderType stage, const VideoCommon::Shader::Registry& registry, | 3134 | ShaderType stage, const VideoCommon::Shader::Registry& registry, |
| 3094 | const Specialization& specialization) { | 3135 | const Specialization& specialization) { |
| 3095 | return SPIRVDecompiler(device, ir, stage, registry, specialization).Assemble(); | 3136 | return SPIRVDecompiler(device, ir, stage, registry, specialization).Assemble(); |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h index 2b0e90396..26381e444 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h | |||
| @@ -15,23 +15,21 @@ | |||
| 15 | #include "video_core/shader/shader_ir.h" | 15 | #include "video_core/shader/shader_ir.h" |
| 16 | 16 | ||
| 17 | namespace Vulkan { | 17 | namespace Vulkan { |
| 18 | class VKDevice; | ||
| 19 | } | ||
| 20 | 18 | ||
| 21 | namespace Vulkan { | 19 | class Device; |
| 22 | 20 | ||
| 23 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 21 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 24 | using UniformTexelEntry = VideoCommon::Shader::Sampler; | 22 | using UniformTexelEntry = VideoCommon::Shader::SamplerEntry; |
| 25 | using SamplerEntry = VideoCommon::Shader::Sampler; | 23 | using SamplerEntry = VideoCommon::Shader::SamplerEntry; |
| 26 | using StorageTexelEntry = VideoCommon::Shader::Image; | 24 | using StorageTexelEntry = VideoCommon::Shader::ImageEntry; |
| 27 | using ImageEntry = VideoCommon::Shader::Image; | 25 | using ImageEntry = VideoCommon::Shader::ImageEntry; |
| 28 | 26 | ||
| 29 | constexpr u32 DESCRIPTOR_SET = 0; | 27 | constexpr u32 DESCRIPTOR_SET = 0; |
| 30 | 28 | ||
| 31 | class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer { | 29 | class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer { |
| 32 | public: | 30 | public: |
| 33 | explicit constexpr ConstBufferEntry(const VideoCommon::Shader::ConstBuffer& entry, u32 index) | 31 | explicit constexpr ConstBufferEntry(const ConstBuffer& entry_, u32 index_) |
| 34 | : VideoCommon::Shader::ConstBuffer{entry}, index{index} {} | 32 | : ConstBuffer{entry_}, index{index_} {} |
| 35 | 33 | ||
| 36 | constexpr u32 GetIndex() const { | 34 | constexpr u32 GetIndex() const { |
| 37 | return index; | 35 | return index; |
| @@ -43,8 +41,8 @@ private: | |||
| 43 | 41 | ||
| 44 | class GlobalBufferEntry { | 42 | class GlobalBufferEntry { |
| 45 | public: | 43 | public: |
| 46 | constexpr explicit GlobalBufferEntry(u32 cbuf_index, u32 cbuf_offset, bool is_written) | 44 | constexpr explicit GlobalBufferEntry(u32 cbuf_index_, u32 cbuf_offset_, bool is_written_) |
| 47 | : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset}, is_written{is_written} {} | 45 | : cbuf_index{cbuf_index_}, cbuf_offset{cbuf_offset_}, is_written{is_written_} {} |
| 48 | 46 | ||
| 49 | constexpr u32 GetCbufIndex() const { | 47 | constexpr u32 GetCbufIndex() const { |
| 50 | return cbuf_index; | 48 | return cbuf_index; |
| @@ -95,6 +93,9 @@ struct Specialization final { | |||
| 95 | std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; | 93 | std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; |
| 96 | std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; | 94 | std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; |
| 97 | bool ndc_minus_one_to_one{}; | 95 | bool ndc_minus_one_to_one{}; |
| 96 | bool early_fragment_tests{}; | ||
| 97 | float alpha_test_ref{}; | ||
| 98 | Maxwell::ComparisonOp alpha_test_func{}; | ||
| 98 | }; | 99 | }; |
| 99 | // Old gcc versions don't consider this trivially copyable. | 100 | // Old gcc versions don't consider this trivially copyable. |
| 100 | // static_assert(std::is_trivially_copyable_v<Specialization>); | 101 | // static_assert(std::is_trivially_copyable_v<Specialization>); |
| @@ -106,7 +107,7 @@ struct SPIRVShader { | |||
| 106 | 107 | ||
| 107 | ShaderEntries GenerateShaderEntries(const VideoCommon::Shader::ShaderIR& ir); | 108 | ShaderEntries GenerateShaderEntries(const VideoCommon::Shader::ShaderIR& ir); |
| 108 | 109 | ||
| 109 | std::vector<u32> Decompile(const VKDevice& device, const VideoCommon::Shader::ShaderIR& ir, | 110 | std::vector<u32> Decompile(const Device& device, const VideoCommon::Shader::ShaderIR& ir, |
| 110 | Tegra::Engines::ShaderType stage, | 111 | Tegra::Engines::ShaderType stage, |
| 111 | const VideoCommon::Shader::Registry& registry, | 112 | const VideoCommon::Shader::Registry& registry, |
| 112 | const Specialization& specialization); | 113 | const Specialization& specialization); |
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp index c1a218d76..aaad4f292 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp | |||
| @@ -7,24 +7,19 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_shader_util.h" | 10 | #include "video_core/renderer_vulkan/vk_shader_util.h" |
| 12 | #include "video_core/renderer_vulkan/wrapper.h" | 11 | #include "video_core/vulkan_common/vulkan_device.h" |
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | 13 | ||
| 14 | namespace Vulkan { | 14 | namespace Vulkan { |
| 15 | 15 | ||
| 16 | vk::ShaderModule BuildShader(const VKDevice& device, std::size_t code_size, const u8* code_data) { | 16 | vk::ShaderModule BuildShader(const Device& device, std::span<const u32> code) { |
| 17 | // Avoid undefined behavior by copying to a staging allocation | ||
| 18 | ASSERT(code_size % sizeof(u32) == 0); | ||
| 19 | const auto data = std::make_unique<u32[]>(code_size / sizeof(u32)); | ||
| 20 | std::memcpy(data.get(), code_data, code_size); | ||
| 21 | |||
| 22 | return device.GetLogical().CreateShaderModule({ | 17 | return device.GetLogical().CreateShaderModule({ |
| 23 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | 18 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, |
| 24 | .pNext = nullptr, | 19 | .pNext = nullptr, |
| 25 | .flags = 0, | 20 | .flags = 0, |
| 26 | .codeSize = code_size, | 21 | .codeSize = static_cast<u32>(code.size_bytes()), |
| 27 | .pCode = data.get(), | 22 | .pCode = code.data(), |
| 28 | }); | 23 | }); |
| 29 | } | 24 | } |
| 30 | 25 | ||
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.h b/src/video_core/renderer_vulkan/vk_shader_util.h index d1d3f3cae..9517cbe84 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.h +++ b/src/video_core/renderer_vulkan/vk_shader_util.h | |||
| @@ -4,13 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <span> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | #include "video_core/renderer_vulkan/wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 9 | 11 | ||
| 10 | namespace Vulkan { | 12 | namespace Vulkan { |
| 11 | 13 | ||
| 12 | class VKDevice; | 14 | class Device; |
| 13 | 15 | ||
| 14 | vk::ShaderModule BuildShader(const VKDevice& device, std::size_t code_size, const u8* code_data); | 16 | vk::ShaderModule BuildShader(const Device& device, std::span<const u32> code); |
| 15 | 17 | ||
| 16 | } // namespace Vulkan | 18 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 2fd3b7f39..1e0b8b922 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -9,17 +9,17 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/bit_util.h" | 10 | #include "common/bit_util.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 12 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 14 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 13 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 15 | #include "video_core/renderer_vulkan/wrapper.h" | 14 | #include "video_core/vulkan_common/vulkan_device.h" |
| 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 16 | 16 | ||
| 17 | namespace Vulkan { | 17 | namespace Vulkan { |
| 18 | 18 | ||
| 19 | VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_) | 19 | VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_) |
| 20 | : buffer{std::move(buffer_)} {} | 20 | : buffer{std::move(buffer_)} {} |
| 21 | 21 | ||
| 22 | VKStagingBufferPool::VKStagingBufferPool(const VKDevice& device_, VKMemoryManager& memory_manager_, | 22 | VKStagingBufferPool::VKStagingBufferPool(const Device& device_, VKMemoryManager& memory_manager_, |
| 23 | VKScheduler& scheduler_) | 23 | VKScheduler& scheduler_) |
| 24 | : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} | 24 | : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} |
| 25 | 25 | ||
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 2dd5049ac..90dadcbbe 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | |||
| @@ -10,11 +10,11 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | 11 | ||
| 12 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 12 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 13 | #include "video_core/renderer_vulkan/wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 14 | 14 | ||
| 15 | namespace Vulkan { | 15 | namespace Vulkan { |
| 16 | 16 | ||
| 17 | class VKDevice; | 17 | class Device; |
| 18 | class VKScheduler; | 18 | class VKScheduler; |
| 19 | 19 | ||
| 20 | struct VKBuffer final { | 20 | struct VKBuffer final { |
| @@ -24,7 +24,7 @@ struct VKBuffer final { | |||
| 24 | 24 | ||
| 25 | class VKStagingBufferPool final { | 25 | class VKStagingBufferPool final { |
| 26 | public: | 26 | public: |
| 27 | explicit VKStagingBufferPool(const VKDevice& device, VKMemoryManager& memory_manager, | 27 | explicit VKStagingBufferPool(const Device& device, VKMemoryManager& memory_manager, |
| 28 | VKScheduler& scheduler); | 28 | VKScheduler& scheduler); |
| 29 | ~VKStagingBufferPool(); | 29 | ~VKStagingBufferPool(); |
| 30 | 30 | ||
| @@ -58,7 +58,7 @@ private: | |||
| 58 | 58 | ||
| 59 | u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2); | 59 | u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2); |
| 60 | 60 | ||
| 61 | const VKDevice& device; | 61 | const Device& device; |
| 62 | VKMemoryManager& memory_manager; | 62 | VKMemoryManager& memory_manager; |
| 63 | VKScheduler& scheduler; | 63 | VKScheduler& scheduler; |
| 64 | 64 | ||
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index 5d2c4a796..1779a2e30 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | ||
| 6 | #include <cstddef> | 7 | #include <cstddef> |
| 7 | #include <iterator> | 8 | #include <iterator> |
| 8 | 9 | ||
| @@ -14,7 +15,7 @@ | |||
| 14 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 15 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 15 | 16 | ||
| 16 | #define OFF(field_name) MAXWELL3D_REG_INDEX(field_name) | 17 | #define OFF(field_name) MAXWELL3D_REG_INDEX(field_name) |
| 17 | #define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / sizeof(u32)) | 18 | #define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / (sizeof(u32))) |
| 18 | 19 | ||
| 19 | namespace Vulkan { | 20 | namespace Vulkan { |
| 20 | 21 | ||
| @@ -29,21 +30,15 @@ using Table = Maxwell3D::DirtyState::Table; | |||
| 29 | using Flags = Maxwell3D::DirtyState::Flags; | 30 | using Flags = Maxwell3D::DirtyState::Flags; |
| 30 | 31 | ||
| 31 | Flags MakeInvalidationFlags() { | 32 | Flags MakeInvalidationFlags() { |
| 33 | static constexpr std::array INVALIDATION_FLAGS{ | ||
| 34 | Viewports, Scissors, DepthBias, BlendConstants, DepthBounds, | ||
| 35 | StencilProperties, CullMode, DepthBoundsEnable, DepthTestEnable, DepthWriteEnable, | ||
| 36 | DepthCompareOp, FrontFace, StencilOp, StencilTestEnable, | ||
| 37 | }; | ||
| 32 | Flags flags{}; | 38 | Flags flags{}; |
| 33 | flags[Viewports] = true; | 39 | for (const int flag : INVALIDATION_FLAGS) { |
| 34 | flags[Scissors] = true; | 40 | flags[flag] = true; |
| 35 | flags[DepthBias] = true; | 41 | } |
| 36 | flags[BlendConstants] = true; | ||
| 37 | flags[DepthBounds] = true; | ||
| 38 | flags[StencilProperties] = true; | ||
| 39 | flags[CullMode] = true; | ||
| 40 | flags[DepthBoundsEnable] = true; | ||
| 41 | flags[DepthTestEnable] = true; | ||
| 42 | flags[DepthWriteEnable] = true; | ||
| 43 | flags[DepthCompareOp] = true; | ||
| 44 | flags[FrontFace] = true; | ||
| 45 | flags[StencilOp] = true; | ||
| 46 | flags[StencilTestEnable] = true; | ||
| 47 | return flags; | 42 | return flags; |
| 48 | } | 43 | } |
| 49 | 44 | ||
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h index 1de789e57..c335d2bdf 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.h +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h | |||
| @@ -52,6 +52,14 @@ public: | |||
| 52 | current_topology = INVALID_TOPOLOGY; | 52 | current_topology = INVALID_TOPOLOGY; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | void InvalidateViewports() { | ||
| 56 | flags[Dirty::Viewports] = true; | ||
| 57 | } | ||
| 58 | |||
| 59 | void InvalidateScissors() { | ||
| 60 | flags[Dirty::Scissors] = true; | ||
| 61 | } | ||
| 62 | |||
| 55 | bool TouchViewports() { | 63 | bool TouchViewports() { |
| 56 | return Exchange(Dirty::Viewports, false); | 64 | return Exchange(Dirty::Viewports, false); |
| 57 | } | 65 | } |
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp index 5218c875b..a09fe084e 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp | |||
| @@ -10,15 +10,19 @@ | |||
| 10 | 10 | ||
| 11 | #include "common/alignment.h" | 11 | #include "common/alignment.h" |
| 12 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 13 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 15 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" | 14 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" |
| 16 | #include "video_core/renderer_vulkan/wrapper.h" | 15 | #include "video_core/vulkan_common/vulkan_device.h" |
| 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 17 | 17 | ||
| 18 | namespace Vulkan { | 18 | namespace Vulkan { |
| 19 | 19 | ||
| 20 | namespace { | 20 | namespace { |
| 21 | 21 | ||
| 22 | constexpr VkBufferUsageFlags BUFFER_USAGE = | ||
| 23 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | | ||
| 24 | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; | ||
| 25 | |||
| 22 | constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000; | 26 | constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000; |
| 23 | constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000; | 27 | constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000; |
| 24 | 28 | ||
| @@ -56,17 +60,16 @@ u32 GetMemoryType(const VkPhysicalDeviceMemoryProperties& properties, | |||
| 56 | 60 | ||
| 57 | } // Anonymous namespace | 61 | } // Anonymous namespace |
| 58 | 62 | ||
| 59 | VKStreamBuffer::VKStreamBuffer(const VKDevice& device_, VKScheduler& scheduler_, | 63 | VKStreamBuffer::VKStreamBuffer(const Device& device_, VKScheduler& scheduler_) |
| 60 | VkBufferUsageFlags usage) | ||
| 61 | : device{device_}, scheduler{scheduler_} { | 64 | : device{device_}, scheduler{scheduler_} { |
| 62 | CreateBuffers(usage); | 65 | CreateBuffers(); |
| 63 | ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE); | 66 | ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE); |
| 64 | ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE); | 67 | ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE); |
| 65 | } | 68 | } |
| 66 | 69 | ||
| 67 | VKStreamBuffer::~VKStreamBuffer() = default; | 70 | VKStreamBuffer::~VKStreamBuffer() = default; |
| 68 | 71 | ||
| 69 | std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) { | 72 | std::pair<u8*, u64> VKStreamBuffer::Map(u64 size, u64 alignment) { |
| 70 | ASSERT(size <= stream_buffer_size); | 73 | ASSERT(size <= stream_buffer_size); |
| 71 | mapped_size = size; | 74 | mapped_size = size; |
| 72 | 75 | ||
| @@ -76,7 +79,6 @@ std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) { | |||
| 76 | 79 | ||
| 77 | WaitPendingOperations(offset); | 80 | WaitPendingOperations(offset); |
| 78 | 81 | ||
| 79 | bool invalidated = false; | ||
| 80 | if (offset + size > stream_buffer_size) { | 82 | if (offset + size > stream_buffer_size) { |
| 81 | // The buffer would overflow, save the amount of used watches and reset the state. | 83 | // The buffer would overflow, save the amount of used watches and reset the state. |
| 82 | invalidation_mark = current_watch_cursor; | 84 | invalidation_mark = current_watch_cursor; |
| @@ -90,11 +92,9 @@ std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) { | |||
| 90 | 92 | ||
| 91 | // Ensure that we don't wait for uncommitted fences. | 93 | // Ensure that we don't wait for uncommitted fences. |
| 92 | scheduler.Flush(); | 94 | scheduler.Flush(); |
| 93 | |||
| 94 | invalidated = true; | ||
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | return {memory.Map(offset, size), offset, invalidated}; | 97 | return std::make_pair(memory.Map(offset, size), offset); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | void VKStreamBuffer::Unmap(u64 size) { | 100 | void VKStreamBuffer::Unmap(u64 size) { |
| @@ -113,20 +113,21 @@ void VKStreamBuffer::Unmap(u64 size) { | |||
| 113 | watch.tick = scheduler.CurrentTick(); | 113 | watch.tick = scheduler.CurrentTick(); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) { | 116 | void VKStreamBuffer::CreateBuffers() { |
| 117 | const auto memory_properties = device.GetPhysical().GetMemoryProperties(); | 117 | const auto memory_properties = device.GetPhysical().GetMemoryProperties(); |
| 118 | const u32 preferred_type = GetMemoryType(memory_properties); | 118 | const u32 preferred_type = GetMemoryType(memory_properties); |
| 119 | const u32 preferred_heap = memory_properties.memoryTypes[preferred_type].heapIndex; | 119 | const u32 preferred_heap = memory_properties.memoryTypes[preferred_type].heapIndex; |
| 120 | 120 | ||
| 121 | // Substract from the preferred heap size some bytes to avoid getting out of memory. | 121 | // Substract from the preferred heap size some bytes to avoid getting out of memory. |
| 122 | const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; | 122 | const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; |
| 123 | const VkDeviceSize allocable_size = heap_size - 9 * 1024 * 1024; | 123 | // As per DXVK's example, using `heap_size / 2` |
| 124 | const VkDeviceSize allocable_size = heap_size / 2; | ||
| 124 | buffer = device.GetLogical().CreateBuffer({ | 125 | buffer = device.GetLogical().CreateBuffer({ |
| 125 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 126 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 126 | .pNext = nullptr, | 127 | .pNext = nullptr, |
| 127 | .flags = 0, | 128 | .flags = 0, |
| 128 | .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size), | 129 | .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size), |
| 129 | .usage = usage, | 130 | .usage = BUFFER_USAGE, |
| 130 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 131 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 131 | .queueFamilyIndexCount = 0, | 132 | .queueFamilyIndexCount = 0, |
| 132 | .pQueueFamilyIndices = nullptr, | 133 | .pQueueFamilyIndices = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h index 5e15ad78f..2e9c8cb46 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.h +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h | |||
| @@ -5,31 +5,29 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <optional> | 7 | #include <optional> |
| 8 | #include <tuple> | 8 | #include <utility> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/renderer_vulkan/wrapper.h" | 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 13 | 13 | ||
| 14 | namespace Vulkan { | 14 | namespace Vulkan { |
| 15 | 15 | ||
| 16 | class VKDevice; | 16 | class Device; |
| 17 | class VKFenceWatch; | 17 | class VKFenceWatch; |
| 18 | class VKScheduler; | 18 | class VKScheduler; |
| 19 | 19 | ||
| 20 | class VKStreamBuffer final { | 20 | class VKStreamBuffer final { |
| 21 | public: | 21 | public: |
| 22 | explicit VKStreamBuffer(const VKDevice& device, VKScheduler& scheduler, | 22 | explicit VKStreamBuffer(const Device& device, VKScheduler& scheduler); |
| 23 | VkBufferUsageFlags usage); | ||
| 24 | ~VKStreamBuffer(); | 23 | ~VKStreamBuffer(); |
| 25 | 24 | ||
| 26 | /** | 25 | /** |
| 27 | * Reserves a region of memory from the stream buffer. | 26 | * Reserves a region of memory from the stream buffer. |
| 28 | * @param size Size to reserve. | 27 | * @param size Size to reserve. |
| 29 | * @returns A tuple in the following order: Raw memory pointer (with offset added), buffer | 28 | * @returns A pair of a raw memory pointer (with offset added), and the buffer offset |
| 30 | * offset and a boolean that's true when buffer has been invalidated. | ||
| 31 | */ | 29 | */ |
| 32 | std::tuple<u8*, u64, bool> Map(u64 size, u64 alignment); | 30 | std::pair<u8*, u64> Map(u64 size, u64 alignment); |
| 33 | 31 | ||
| 34 | /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy. | 32 | /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy. |
| 35 | void Unmap(u64 size); | 33 | void Unmap(u64 size); |
| @@ -49,14 +47,14 @@ private: | |||
| 49 | }; | 47 | }; |
| 50 | 48 | ||
| 51 | /// Creates Vulkan buffer handles committing the required the required memory. | 49 | /// Creates Vulkan buffer handles committing the required the required memory. |
| 52 | void CreateBuffers(VkBufferUsageFlags usage); | 50 | void CreateBuffers(); |
| 53 | 51 | ||
| 54 | /// Increases the amount of watches available. | 52 | /// Increases the amount of watches available. |
| 55 | void ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size); | 53 | void ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size); |
| 56 | 54 | ||
| 57 | void WaitPendingOperations(u64 requested_upper_bound); | 55 | void WaitPendingOperations(u64 requested_upper_bound); |
| 58 | 56 | ||
| 59 | const VKDevice& device; ///< Vulkan device manager. | 57 | const Device& device; ///< Vulkan device manager. |
| 60 | VKScheduler& scheduler; ///< Command scheduler. | 58 | VKScheduler& scheduler; ///< Command scheduler. |
| 61 | 59 | ||
| 62 | vk::Buffer buffer; ///< Mapped buffer. | 60 | vk::Buffer buffer; ///< Mapped buffer. |
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 9636a7c65..725a2a05d 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp | |||
| @@ -11,10 +11,10 @@ | |||
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/frontend/framebuffer_layout.h" | 13 | #include "core/frontend/framebuffer_layout.h" |
| 14 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 16 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 15 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 17 | #include "video_core/renderer_vulkan/wrapper.h" | 16 | #include "video_core/vulkan_common/vulkan_device.h" |
| 17 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 18 | 18 | ||
| 19 | namespace Vulkan { | 19 | namespace Vulkan { |
| 20 | 20 | ||
| @@ -56,7 +56,7 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi | |||
| 56 | 56 | ||
| 57 | } // Anonymous namespace | 57 | } // Anonymous namespace |
| 58 | 58 | ||
| 59 | VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const VKDevice& device_, VKScheduler& scheduler_) | 59 | VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const Device& device_, VKScheduler& scheduler_) |
| 60 | : surface{surface_}, device{device_}, scheduler{scheduler_} {} | 60 | : surface{surface_}, device{device_}, scheduler{scheduler_} {} |
| 61 | 61 | ||
| 62 | VKSwapchain::~VKSwapchain() = default; | 62 | VKSwapchain::~VKSwapchain() = default; |
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index 6b39befdf..2eadd62b3 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/renderer_vulkan/wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | namespace Layout { | 12 | namespace Layout { |
| 13 | struct FramebufferLayout; | 13 | struct FramebufferLayout; |
| @@ -15,12 +15,12 @@ struct FramebufferLayout; | |||
| 15 | 15 | ||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | class VKDevice; | 18 | class Device; |
| 19 | class VKScheduler; | 19 | class VKScheduler; |
| 20 | 20 | ||
| 21 | class VKSwapchain { | 21 | class VKSwapchain { |
| 22 | public: | 22 | public: |
| 23 | explicit VKSwapchain(VkSurfaceKHR surface, const VKDevice& device, VKScheduler& scheduler); | 23 | explicit VKSwapchain(VkSurfaceKHR surface, const Device& device, VKScheduler& scheduler); |
| 24 | ~VKSwapchain(); | 24 | ~VKSwapchain(); |
| 25 | 25 | ||
| 26 | /// Creates (or recreates) the swapchain with a given size. | 26 | /// Creates (or recreates) the swapchain with a given size. |
| @@ -73,7 +73,7 @@ private: | |||
| 73 | void Destroy(); | 73 | void Destroy(); |
| 74 | 74 | ||
| 75 | const VkSurfaceKHR surface; | 75 | const VkSurfaceKHR surface; |
| 76 | const VKDevice& device; | 76 | const Device& device; |
| 77 | VKScheduler& scheduler; | 77 | VKScheduler& scheduler; |
| 78 | 78 | ||
| 79 | vk::SwapchainKHR swapchain; | 79 | vk::SwapchainKHR swapchain; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index f2c8f2ae1..bd11de012 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -4,613 +4,1105 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <cstddef> | 7 | #include <span> |
| 8 | #include <cstring> | ||
| 9 | #include <memory> | ||
| 10 | #include <variant> | ||
| 11 | #include <vector> | 8 | #include <vector> |
| 12 | 9 | ||
| 13 | #include "common/assert.h" | 10 | #include "video_core/engines/fermi_2d.h" |
| 14 | #include "common/common_types.h" | 11 | #include "video_core/renderer_vulkan/blit_image.h" |
| 15 | #include "core/core.h" | ||
| 16 | #include "video_core/engines/maxwell_3d.h" | ||
| 17 | #include "video_core/morton.h" | ||
| 18 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 19 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 20 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 13 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 21 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 14 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 22 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 15 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 23 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 16 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 24 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 17 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 25 | #include "video_core/renderer_vulkan/wrapper.h" | 18 | #include "video_core/vulkan_common/vulkan_device.h" |
| 26 | #include "video_core/surface.h" | 19 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 27 | 20 | ||
| 28 | namespace Vulkan { | 21 | namespace Vulkan { |
| 29 | 22 | ||
| 30 | using VideoCore::MortonSwizzle; | 23 | using Tegra::Engines::Fermi2D; |
| 31 | using VideoCore::MortonSwizzleMode; | ||
| 32 | |||
| 33 | using Tegra::Texture::SwizzleSource; | 24 | using Tegra::Texture::SwizzleSource; |
| 34 | using VideoCore::Surface::PixelFormat; | 25 | using Tegra::Texture::TextureMipmapFilter; |
| 35 | using VideoCore::Surface::SurfaceTarget; | 26 | using VideoCommon::BufferImageCopy; |
| 27 | using VideoCommon::ImageInfo; | ||
| 28 | using VideoCommon::ImageType; | ||
| 29 | using VideoCommon::SubresourceRange; | ||
| 30 | using VideoCore::Surface::IsPixelFormatASTC; | ||
| 36 | 31 | ||
| 37 | namespace { | 32 | namespace { |
| 38 | 33 | ||
| 39 | VkImageType SurfaceTargetToImage(SurfaceTarget target) { | 34 | constexpr std::array ATTACHMENT_REFERENCES{ |
| 40 | switch (target) { | 35 | VkAttachmentReference{0, VK_IMAGE_LAYOUT_GENERAL}, |
| 41 | case SurfaceTarget::Texture1D: | 36 | VkAttachmentReference{1, VK_IMAGE_LAYOUT_GENERAL}, |
| 42 | case SurfaceTarget::Texture1DArray: | 37 | VkAttachmentReference{2, VK_IMAGE_LAYOUT_GENERAL}, |
| 38 | VkAttachmentReference{3, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 39 | VkAttachmentReference{4, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 40 | VkAttachmentReference{5, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 41 | VkAttachmentReference{6, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 42 | VkAttachmentReference{7, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 43 | VkAttachmentReference{8, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 44 | }; | ||
| 45 | |||
| 46 | constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | ||
| 47 | if (color == std::array<float, 4>{0, 0, 0, 0}) { | ||
| 48 | return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; | ||
| 49 | } else if (color == std::array<float, 4>{0, 0, 0, 1}) { | ||
| 50 | return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; | ||
| 51 | } else if (color == std::array<float, 4>{1, 1, 1, 1}) { | ||
| 52 | return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; | ||
| 53 | } | ||
| 54 | if (color[0] + color[1] + color[2] > 1.35f) { | ||
| 55 | // If color elements are brighter than roughly 0.5 average, use white border | ||
| 56 | return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; | ||
| 57 | } else if (color[3] > 0.5f) { | ||
| 58 | return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; | ||
| 59 | } else { | ||
| 60 | return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | [[nodiscard]] VkImageType ConvertImageType(const ImageType type) { | ||
| 65 | switch (type) { | ||
| 66 | case ImageType::e1D: | ||
| 43 | return VK_IMAGE_TYPE_1D; | 67 | return VK_IMAGE_TYPE_1D; |
| 44 | case SurfaceTarget::Texture2D: | 68 | case ImageType::e2D: |
| 45 | case SurfaceTarget::Texture2DArray: | 69 | case ImageType::Linear: |
| 46 | case SurfaceTarget::TextureCubemap: | ||
| 47 | case SurfaceTarget::TextureCubeArray: | ||
| 48 | return VK_IMAGE_TYPE_2D; | 70 | return VK_IMAGE_TYPE_2D; |
| 49 | case SurfaceTarget::Texture3D: | 71 | case ImageType::e3D: |
| 50 | return VK_IMAGE_TYPE_3D; | 72 | return VK_IMAGE_TYPE_3D; |
| 51 | case SurfaceTarget::TextureBuffer: | 73 | case ImageType::Buffer: |
| 52 | UNREACHABLE(); | 74 | break; |
| 53 | return {}; | ||
| 54 | } | 75 | } |
| 55 | UNREACHABLE_MSG("Unknown texture target={}", static_cast<u32>(target)); | 76 | UNREACHABLE_MSG("Invalid image type={}", type); |
| 56 | return {}; | 77 | return {}; |
| 57 | } | 78 | } |
| 58 | 79 | ||
| 59 | VkImageAspectFlags PixelFormatToImageAspect(PixelFormat pixel_format) { | 80 | [[nodiscard]] VkSampleCountFlagBits ConvertSampleCount(u32 num_samples) { |
| 60 | if (pixel_format < PixelFormat::MaxColorFormat) { | 81 | switch (num_samples) { |
| 61 | return VK_IMAGE_ASPECT_COLOR_BIT; | 82 | case 1: |
| 62 | } else if (pixel_format < PixelFormat::MaxDepthFormat) { | 83 | return VK_SAMPLE_COUNT_1_BIT; |
| 63 | return VK_IMAGE_ASPECT_DEPTH_BIT; | 84 | case 2: |
| 64 | } else if (pixel_format < PixelFormat::MaxDepthStencilFormat) { | 85 | return VK_SAMPLE_COUNT_2_BIT; |
| 65 | return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; | 86 | case 4: |
| 66 | } else { | 87 | return VK_SAMPLE_COUNT_4_BIT; |
| 67 | UNREACHABLE_MSG("Invalid pixel format={}", static_cast<int>(pixel_format)); | 88 | case 8: |
| 68 | return VK_IMAGE_ASPECT_COLOR_BIT; | 89 | return VK_SAMPLE_COUNT_8_BIT; |
| 90 | case 16: | ||
| 91 | return VK_SAMPLE_COUNT_16_BIT; | ||
| 92 | default: | ||
| 93 | UNREACHABLE_MSG("Invalid number of samples={}", num_samples); | ||
| 94 | return VK_SAMPLE_COUNT_1_BIT; | ||
| 69 | } | 95 | } |
| 70 | } | 96 | } |
| 71 | 97 | ||
| 72 | VkImageViewType GetImageViewType(SurfaceTarget target) { | 98 | [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) { |
| 73 | switch (target) { | 99 | const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, info.format); |
| 74 | case SurfaceTarget::Texture1D: | 100 | VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| 75 | return VK_IMAGE_VIEW_TYPE_1D; | 101 | if (info.type == ImageType::e2D && info.resources.layers >= 6 && |
| 76 | case SurfaceTarget::Texture2D: | 102 | info.size.width == info.size.height) { |
| 77 | return VK_IMAGE_VIEW_TYPE_2D; | 103 | flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; |
| 78 | case SurfaceTarget::Texture3D: | ||
| 79 | return VK_IMAGE_VIEW_TYPE_3D; | ||
| 80 | case SurfaceTarget::Texture1DArray: | ||
| 81 | return VK_IMAGE_VIEW_TYPE_1D_ARRAY; | ||
| 82 | case SurfaceTarget::Texture2DArray: | ||
| 83 | return VK_IMAGE_VIEW_TYPE_2D_ARRAY; | ||
| 84 | case SurfaceTarget::TextureCubemap: | ||
| 85 | return VK_IMAGE_VIEW_TYPE_CUBE; | ||
| 86 | case SurfaceTarget::TextureCubeArray: | ||
| 87 | return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; | ||
| 88 | case SurfaceTarget::TextureBuffer: | ||
| 89 | break; | ||
| 90 | } | 104 | } |
| 91 | UNREACHABLE(); | 105 | if (info.type == ImageType::e3D) { |
| 92 | return {}; | 106 | flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; |
| 93 | } | 107 | } |
| 94 | 108 | VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | | |
| 95 | vk::Buffer CreateBuffer(const VKDevice& device, const SurfaceParams& params, | 109 | VK_IMAGE_USAGE_SAMPLED_BIT; |
| 96 | std::size_t host_memory_size) { | 110 | if (format_info.attachable) { |
| 97 | // TODO(Rodrigo): Move texture buffer creation to the buffer cache | 111 | switch (VideoCore::Surface::GetFormatType(info.format)) { |
| 98 | return device.GetLogical().CreateBuffer({ | 112 | case VideoCore::Surface::SurfaceType::ColorTexture: |
| 99 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 113 | usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
| 114 | break; | ||
| 115 | case VideoCore::Surface::SurfaceType::Depth: | ||
| 116 | case VideoCore::Surface::SurfaceType::DepthStencil: | ||
| 117 | usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; | ||
| 118 | break; | ||
| 119 | default: | ||
| 120 | UNREACHABLE_MSG("Invalid surface type"); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | if (format_info.storage) { | ||
| 124 | usage |= VK_IMAGE_USAGE_STORAGE_BIT; | ||
| 125 | } | ||
| 126 | const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples); | ||
| 127 | return VkImageCreateInfo{ | ||
| 128 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | ||
| 100 | .pNext = nullptr, | 129 | .pNext = nullptr, |
| 101 | .flags = 0, | 130 | .flags = flags, |
| 102 | .size = static_cast<VkDeviceSize>(host_memory_size), | 131 | .imageType = ConvertImageType(info.type), |
| 103 | .usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | | 132 | .format = format_info.format, |
| 104 | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | | 133 | .extent = |
| 105 | VK_BUFFER_USAGE_TRANSFER_DST_BIT, | 134 | { |
| 135 | .width = info.size.width >> samples_x, | ||
| 136 | .height = info.size.height >> samples_y, | ||
| 137 | .depth = info.size.depth, | ||
| 138 | }, | ||
| 139 | .mipLevels = static_cast<u32>(info.resources.levels), | ||
| 140 | .arrayLayers = static_cast<u32>(info.resources.layers), | ||
| 141 | .samples = ConvertSampleCount(info.num_samples), | ||
| 142 | .tiling = VK_IMAGE_TILING_OPTIMAL, | ||
| 143 | .usage = usage, | ||
| 106 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 144 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 107 | .queueFamilyIndexCount = 0, | 145 | .queueFamilyIndexCount = 0, |
| 108 | .pQueueFamilyIndices = nullptr, | 146 | .pQueueFamilyIndices = nullptr, |
| 109 | }); | 147 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 110 | } | ||
| 111 | |||
| 112 | VkBufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device, | ||
| 113 | const SurfaceParams& params, VkBuffer buffer, | ||
| 114 | std::size_t host_memory_size) { | ||
| 115 | ASSERT(params.IsBuffer()); | ||
| 116 | |||
| 117 | return { | ||
| 118 | .sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, | ||
| 119 | .pNext = nullptr, | ||
| 120 | .flags = 0, | ||
| 121 | .buffer = buffer, | ||
| 122 | .format = | ||
| 123 | MaxwellToVK::SurfaceFormat(device, FormatType::Buffer, params.pixel_format).format, | ||
| 124 | .offset = 0, | ||
| 125 | .range = static_cast<VkDeviceSize>(host_memory_size), | ||
| 126 | }; | 148 | }; |
| 127 | } | 149 | } |
| 128 | 150 | ||
| 129 | VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { | 151 | [[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) { |
| 130 | ASSERT(!params.IsBuffer()); | 152 | if (info.type == ImageType::Buffer) { |
| 131 | 153 | return vk::Image{}; | |
| 132 | const auto [format, attachable, storage] = | 154 | } |
| 133 | MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, params.pixel_format); | 155 | return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info)); |
| 156 | } | ||
| 134 | 157 | ||
| 135 | VkImageCreateInfo ci{ | 158 | [[nodiscard]] vk::Buffer MakeBuffer(const Device& device, const ImageInfo& info) { |
| 136 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 159 | if (info.type != ImageType::Buffer) { |
| 160 | return vk::Buffer{}; | ||
| 161 | } | ||
| 162 | const size_t bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format); | ||
| 163 | return device.GetLogical().CreateBuffer(VkBufferCreateInfo{ | ||
| 164 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 137 | .pNext = nullptr, | 165 | .pNext = nullptr, |
| 138 | .flags = 0, | 166 | .flags = 0, |
| 139 | .imageType = SurfaceTargetToImage(params.target), | 167 | .size = info.size.width * bytes_per_block, |
| 140 | .format = format, | 168 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 141 | .extent = {}, | 169 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | |
| 142 | .mipLevels = params.num_levels, | 170 | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, |
| 143 | .arrayLayers = static_cast<u32>(params.GetNumLayers()), | ||
| 144 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 145 | .tiling = VK_IMAGE_TILING_OPTIMAL, | ||
| 146 | .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | | ||
| 147 | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, | ||
| 148 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 171 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 149 | .queueFamilyIndexCount = 0, | 172 | .queueFamilyIndexCount = 0, |
| 150 | .pQueueFamilyIndices = nullptr, | 173 | .pQueueFamilyIndices = nullptr, |
| 151 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 174 | }); |
| 152 | }; | ||
| 153 | if (attachable) { | ||
| 154 | ci.usage |= params.IsPixelFormatZeta() ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | ||
| 155 | : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; | ||
| 156 | } | ||
| 157 | if (storage) { | ||
| 158 | ci.usage |= VK_IMAGE_USAGE_STORAGE_BIT; | ||
| 159 | } | ||
| 160 | |||
| 161 | switch (params.target) { | ||
| 162 | case SurfaceTarget::TextureCubemap: | ||
| 163 | case SurfaceTarget::TextureCubeArray: | ||
| 164 | ci.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; | ||
| 165 | [[fallthrough]]; | ||
| 166 | case SurfaceTarget::Texture1D: | ||
| 167 | case SurfaceTarget::Texture1DArray: | ||
| 168 | case SurfaceTarget::Texture2D: | ||
| 169 | case SurfaceTarget::Texture2DArray: | ||
| 170 | ci.extent = {params.width, params.height, 1}; | ||
| 171 | break; | ||
| 172 | case SurfaceTarget::Texture3D: | ||
| 173 | ci.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; | ||
| 174 | ci.extent = {params.width, params.height, params.depth}; | ||
| 175 | break; | ||
| 176 | case SurfaceTarget::TextureBuffer: | ||
| 177 | UNREACHABLE(); | ||
| 178 | } | ||
| 179 | |||
| 180 | return ci; | ||
| 181 | } | 175 | } |
| 182 | 176 | ||
| 183 | u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, Tegra::Texture::SwizzleSource y_source, | 177 | [[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { |
| 184 | Tegra::Texture::SwizzleSource z_source, Tegra::Texture::SwizzleSource w_source) { | 178 | switch (VideoCore::Surface::GetFormatType(format)) { |
| 185 | return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) | | 179 | case VideoCore::Surface::SurfaceType::ColorTexture: |
| 186 | (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source); | 180 | return VK_IMAGE_ASPECT_COLOR_BIT; |
| 181 | case VideoCore::Surface::SurfaceType::Depth: | ||
| 182 | return VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 183 | case VideoCore::Surface::SurfaceType::DepthStencil: | ||
| 184 | return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; | ||
| 185 | default: | ||
| 186 | UNREACHABLE_MSG("Invalid surface type"); | ||
| 187 | return VkImageAspectFlags{}; | ||
| 188 | } | ||
| 187 | } | 189 | } |
| 188 | 190 | ||
| 189 | } // Anonymous namespace | 191 | [[nodiscard]] VkImageAspectFlags ImageViewAspectMask(const VideoCommon::ImageViewInfo& info) { |
| 190 | 192 | if (info.IsRenderTarget()) { | |
| 191 | CachedSurface::CachedSurface(const VKDevice& device, VKMemoryManager& memory_manager, | 193 | return ImageAspectMask(info.format); |
| 192 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool, | ||
| 193 | GPUVAddr gpu_addr, const SurfaceParams& params) | ||
| 194 | : SurfaceBase<View>{gpu_addr, params, device.IsOptimalAstcSupported()}, device{device}, | ||
| 195 | memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{staging_pool} { | ||
| 196 | if (params.IsBuffer()) { | ||
| 197 | buffer = CreateBuffer(device, params, host_memory_size); | ||
| 198 | commit = memory_manager.Commit(buffer, false); | ||
| 199 | |||
| 200 | const auto buffer_view_ci = | ||
| 201 | GenerateBufferViewCreateInfo(device, params, *buffer, host_memory_size); | ||
| 202 | format = buffer_view_ci.format; | ||
| 203 | |||
| 204 | buffer_view = device.GetLogical().CreateBufferView(buffer_view_ci); | ||
| 205 | } else { | ||
| 206 | const auto image_ci = GenerateImageCreateInfo(device, params); | ||
| 207 | format = image_ci.format; | ||
| 208 | |||
| 209 | image.emplace(device, scheduler, image_ci, PixelFormatToImageAspect(params.pixel_format)); | ||
| 210 | commit = memory_manager.Commit(image->GetHandle(), false); | ||
| 211 | } | 194 | } |
| 212 | 195 | const bool is_first = info.Swizzle()[0] == SwizzleSource::R; | |
| 213 | // TODO(Rodrigo): Move this to a virtual function. | 196 | switch (info.format) { |
| 214 | u32 num_layers = 1; | 197 | case PixelFormat::D24_UNORM_S8_UINT: |
| 215 | if (params.is_layered || params.target == SurfaceTarget::Texture3D) { | 198 | case PixelFormat::D32_FLOAT_S8_UINT: |
| 216 | num_layers = params.depth; | 199 | return is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT; |
| 200 | case PixelFormat::S8_UINT_D24_UNORM: | ||
| 201 | return is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 202 | case PixelFormat::D16_UNORM: | ||
| 203 | case PixelFormat::D32_FLOAT: | ||
| 204 | return VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 205 | default: | ||
| 206 | return VK_IMAGE_ASPECT_COLOR_BIT; | ||
| 217 | } | 207 | } |
| 218 | main_view = CreateView(ViewParams(params.target, 0, num_layers, 0, params.num_levels)); | ||
| 219 | } | 208 | } |
| 220 | 209 | ||
| 221 | CachedSurface::~CachedSurface() = default; | 210 | [[nodiscard]] VkAttachmentDescription AttachmentDescription(const Device& device, |
| 222 | 211 | const ImageView* image_view) { | |
| 223 | void CachedSurface::UploadTexture(const std::vector<u8>& staging_buffer) { | 212 | const auto pixel_format = image_view->format; |
| 224 | // To upload data we have to be outside of a renderpass | 213 | return VkAttachmentDescription{ |
| 225 | scheduler.RequestOutsideRenderPassOperationContext(); | 214 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, |
| 215 | .format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format).format, | ||
| 216 | .samples = image_view->Samples(), | ||
| 217 | .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 218 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 219 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 220 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 221 | .initialLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 222 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 223 | }; | ||
| 224 | } | ||
| 226 | 225 | ||
| 227 | if (params.IsBuffer()) { | 226 | [[nodiscard]] VkComponentSwizzle ComponentSwizzle(SwizzleSource swizzle) { |
| 228 | UploadBuffer(staging_buffer); | 227 | switch (swizzle) { |
| 229 | } else { | 228 | case SwizzleSource::Zero: |
| 230 | UploadImage(staging_buffer); | 229 | return VK_COMPONENT_SWIZZLE_ZERO; |
| 230 | case SwizzleSource::R: | ||
| 231 | return VK_COMPONENT_SWIZZLE_R; | ||
| 232 | case SwizzleSource::G: | ||
| 233 | return VK_COMPONENT_SWIZZLE_G; | ||
| 234 | case SwizzleSource::B: | ||
| 235 | return VK_COMPONENT_SWIZZLE_B; | ||
| 236 | case SwizzleSource::A: | ||
| 237 | return VK_COMPONENT_SWIZZLE_A; | ||
| 238 | case SwizzleSource::OneFloat: | ||
| 239 | case SwizzleSource::OneInt: | ||
| 240 | return VK_COMPONENT_SWIZZLE_ONE; | ||
| 231 | } | 241 | } |
| 242 | UNREACHABLE_MSG("Invalid swizzle={}", swizzle); | ||
| 243 | return VK_COMPONENT_SWIZZLE_ZERO; | ||
| 232 | } | 244 | } |
| 233 | 245 | ||
| 234 | void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { | 246 | [[nodiscard]] VkImageViewType ImageViewType(VideoCommon::ImageViewType type) { |
| 235 | UNIMPLEMENTED_IF(params.IsBuffer()); | 247 | switch (type) { |
| 236 | 248 | case VideoCommon::ImageViewType::e1D: | |
| 237 | if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5_UNORM) { | 249 | return VK_IMAGE_VIEW_TYPE_1D; |
| 238 | LOG_WARNING(Render_Vulkan, "A1B5G5R5 flushing is stubbed"); | 250 | case VideoCommon::ImageViewType::e2D: |
| 251 | return VK_IMAGE_VIEW_TYPE_2D; | ||
| 252 | case VideoCommon::ImageViewType::Cube: | ||
| 253 | return VK_IMAGE_VIEW_TYPE_CUBE; | ||
| 254 | case VideoCommon::ImageViewType::e3D: | ||
| 255 | return VK_IMAGE_VIEW_TYPE_3D; | ||
| 256 | case VideoCommon::ImageViewType::e1DArray: | ||
| 257 | return VK_IMAGE_VIEW_TYPE_1D_ARRAY; | ||
| 258 | case VideoCommon::ImageViewType::e2DArray: | ||
| 259 | return VK_IMAGE_VIEW_TYPE_2D_ARRAY; | ||
| 260 | case VideoCommon::ImageViewType::CubeArray: | ||
| 261 | return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; | ||
| 262 | case VideoCommon::ImageViewType::Rect: | ||
| 263 | LOG_WARNING(Render_Vulkan, "Unnormalized image view type not supported"); | ||
| 264 | return VK_IMAGE_VIEW_TYPE_2D; | ||
| 265 | case VideoCommon::ImageViewType::Buffer: | ||
| 266 | UNREACHABLE_MSG("Texture buffers can't be image views"); | ||
| 267 | return VK_IMAGE_VIEW_TYPE_1D; | ||
| 239 | } | 268 | } |
| 269 | UNREACHABLE_MSG("Invalid image view type={}", type); | ||
| 270 | return VK_IMAGE_VIEW_TYPE_2D; | ||
| 271 | } | ||
| 240 | 272 | ||
| 241 | // We can't copy images to buffers inside a renderpass | 273 | [[nodiscard]] VkImageSubresourceLayers MakeImageSubresourceLayers( |
| 242 | scheduler.RequestOutsideRenderPassOperationContext(); | 274 | VideoCommon::SubresourceLayers subresource, VkImageAspectFlags aspect_mask) { |
| 275 | return VkImageSubresourceLayers{ | ||
| 276 | .aspectMask = aspect_mask, | ||
| 277 | .mipLevel = static_cast<u32>(subresource.base_level), | ||
| 278 | .baseArrayLayer = static_cast<u32>(subresource.base_layer), | ||
| 279 | .layerCount = static_cast<u32>(subresource.num_layers), | ||
| 280 | }; | ||
| 281 | } | ||
| 243 | 282 | ||
| 244 | FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, | 283 | [[nodiscard]] VkOffset3D MakeOffset3D(VideoCommon::Offset3D offset3d) { |
| 245 | VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); | 284 | return VkOffset3D{ |
| 285 | .x = offset3d.x, | ||
| 286 | .y = offset3d.y, | ||
| 287 | .z = offset3d.z, | ||
| 288 | }; | ||
| 289 | } | ||
| 246 | 290 | ||
| 247 | const auto& buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); | 291 | [[nodiscard]] VkExtent3D MakeExtent3D(VideoCommon::Extent3D extent3d) { |
| 248 | // TODO(Rodrigo): Do this in a single copy | 292 | return VkExtent3D{ |
| 249 | for (u32 level = 0; level < params.num_levels; ++level) { | 293 | .width = static_cast<u32>(extent3d.width), |
| 250 | scheduler.Record([image = *image->GetHandle(), buffer = *buffer.handle, | 294 | .height = static_cast<u32>(extent3d.height), |
| 251 | copy = GetBufferImageCopy(level)](vk::CommandBuffer cmdbuf) { | 295 | .depth = static_cast<u32>(extent3d.depth), |
| 252 | cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy); | 296 | }; |
| 253 | }); | 297 | } |
| 254 | } | ||
| 255 | scheduler.Finish(); | ||
| 256 | 298 | ||
| 257 | // TODO(Rodrigo): Use an intern buffer for staging buffers and avoid this unnecessary memcpy. | 299 | [[nodiscard]] VkImageCopy MakeImageCopy(const VideoCommon::ImageCopy& copy, |
| 258 | std::memcpy(staging_buffer.data(), buffer.commit->Map(host_memory_size), host_memory_size); | 300 | VkImageAspectFlags aspect_mask) noexcept { |
| 301 | return VkImageCopy{ | ||
| 302 | .srcSubresource = MakeImageSubresourceLayers(copy.src_subresource, aspect_mask), | ||
| 303 | .srcOffset = MakeOffset3D(copy.src_offset), | ||
| 304 | .dstSubresource = MakeImageSubresourceLayers(copy.dst_subresource, aspect_mask), | ||
| 305 | .dstOffset = MakeOffset3D(copy.dst_offset), | ||
| 306 | .extent = MakeExtent3D(copy.extent), | ||
| 307 | }; | ||
| 259 | } | 308 | } |
| 260 | 309 | ||
| 261 | void CachedSurface::DecorateSurfaceName() { | 310 | [[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies( |
| 262 | // TODO(Rodrigo): Add name decorations | 311 | std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) { |
| 312 | std::vector<VkBufferCopy> result(copies.size()); | ||
| 313 | std::ranges::transform( | ||
| 314 | copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) { | ||
| 315 | return VkBufferCopy{ | ||
| 316 | .srcOffset = static_cast<VkDeviceSize>(copy.src_offset + buffer_offset), | ||
| 317 | .dstOffset = static_cast<VkDeviceSize>(copy.dst_offset), | ||
| 318 | .size = static_cast<VkDeviceSize>(copy.size), | ||
| 319 | }; | ||
| 320 | }); | ||
| 321 | return result; | ||
| 263 | } | 322 | } |
| 264 | 323 | ||
| 265 | View CachedSurface::CreateView(const ViewParams& params) { | 324 | [[nodiscard]] std::vector<VkBufferImageCopy> TransformBufferImageCopies( |
| 266 | // TODO(Rodrigo): Add name decorations | 325 | std::span<const BufferImageCopy> copies, size_t buffer_offset, VkImageAspectFlags aspect_mask) { |
| 267 | return views[params] = std::make_shared<CachedSurfaceView>(device, *this, params); | 326 | struct Maker { |
| 327 | VkBufferImageCopy operator()(const BufferImageCopy& copy) const { | ||
| 328 | return VkBufferImageCopy{ | ||
| 329 | .bufferOffset = copy.buffer_offset + buffer_offset, | ||
| 330 | .bufferRowLength = copy.buffer_row_length, | ||
| 331 | .bufferImageHeight = copy.buffer_image_height, | ||
| 332 | .imageSubresource = | ||
| 333 | { | ||
| 334 | .aspectMask = aspect_mask, | ||
| 335 | .mipLevel = static_cast<u32>(copy.image_subresource.base_level), | ||
| 336 | .baseArrayLayer = static_cast<u32>(copy.image_subresource.base_layer), | ||
| 337 | .layerCount = static_cast<u32>(copy.image_subresource.num_layers), | ||
| 338 | }, | ||
| 339 | .imageOffset = | ||
| 340 | { | ||
| 341 | .x = copy.image_offset.x, | ||
| 342 | .y = copy.image_offset.y, | ||
| 343 | .z = copy.image_offset.z, | ||
| 344 | }, | ||
| 345 | .imageExtent = | ||
| 346 | { | ||
| 347 | .width = copy.image_extent.width, | ||
| 348 | .height = copy.image_extent.height, | ||
| 349 | .depth = copy.image_extent.depth, | ||
| 350 | }, | ||
| 351 | }; | ||
| 352 | } | ||
| 353 | size_t buffer_offset; | ||
| 354 | VkImageAspectFlags aspect_mask; | ||
| 355 | }; | ||
| 356 | if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | ||
| 357 | std::vector<VkBufferImageCopy> result(copies.size() * 2); | ||
| 358 | std::ranges::transform(copies, result.begin(), | ||
| 359 | Maker{buffer_offset, VK_IMAGE_ASPECT_DEPTH_BIT}); | ||
| 360 | std::ranges::transform(copies, result.begin() + copies.size(), | ||
| 361 | Maker{buffer_offset, VK_IMAGE_ASPECT_STENCIL_BIT}); | ||
| 362 | return result; | ||
| 363 | } else { | ||
| 364 | std::vector<VkBufferImageCopy> result(copies.size()); | ||
| 365 | std::ranges::transform(copies, result.begin(), Maker{buffer_offset, aspect_mask}); | ||
| 366 | return result; | ||
| 367 | } | ||
| 268 | } | 368 | } |
| 269 | 369 | ||
| 270 | void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) { | 370 | [[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(VkImageAspectFlags aspect_mask, |
| 271 | const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); | 371 | const SubresourceRange& range) { |
| 272 | std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); | 372 | return VkImageSubresourceRange{ |
| 373 | .aspectMask = aspect_mask, | ||
| 374 | .baseMipLevel = static_cast<u32>(range.base.level), | ||
| 375 | .levelCount = static_cast<u32>(range.extent.levels), | ||
| 376 | .baseArrayLayer = static_cast<u32>(range.base.layer), | ||
| 377 | .layerCount = static_cast<u32>(range.extent.layers), | ||
| 378 | }; | ||
| 379 | } | ||
| 273 | 380 | ||
| 274 | scheduler.Record([src_buffer = *src_buffer.handle, dst_buffer = *buffer, | 381 | [[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(const ImageView* image_view) { |
| 275 | size = host_memory_size](vk::CommandBuffer cmdbuf) { | 382 | SubresourceRange range = image_view->range; |
| 276 | VkBufferCopy copy; | 383 | if (True(image_view->flags & VideoCommon::ImageViewFlagBits::Slice)) { |
| 277 | copy.srcOffset = 0; | 384 | // Slice image views always affect a single layer, but their subresource range corresponds |
| 278 | copy.dstOffset = 0; | 385 | // to the slice. Override the value to affect a single layer. |
| 279 | copy.size = size; | 386 | range.base.layer = 0; |
| 280 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); | 387 | range.extent.layers = 1; |
| 388 | } | ||
| 389 | return MakeSubresourceRange(ImageAspectMask(image_view->format), range); | ||
| 390 | } | ||
| 281 | 391 | ||
| 282 | VkBufferMemoryBarrier barrier; | 392 | [[nodiscard]] VkImageSubresourceLayers MakeSubresourceLayers(const ImageView* image_view) { |
| 283 | barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; | 393 | return VkImageSubresourceLayers{ |
| 284 | barrier.pNext = nullptr; | 394 | .aspectMask = ImageAspectMask(image_view->format), |
| 285 | barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | 395 | .mipLevel = static_cast<u32>(image_view->range.base.level), |
| 286 | barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | 396 | .baseArrayLayer = static_cast<u32>(image_view->range.base.layer), |
| 287 | barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // They'll be ignored anyway | 397 | .layerCount = static_cast<u32>(image_view->range.extent.layers), |
| 288 | barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | 398 | }; |
| 289 | barrier.buffer = dst_buffer; | ||
| 290 | barrier.offset = 0; | ||
| 291 | barrier.size = size; | ||
| 292 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, | ||
| 293 | 0, {}, barrier, {}); | ||
| 294 | }); | ||
| 295 | } | 399 | } |
| 296 | 400 | ||
| 297 | void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) { | 401 | [[nodiscard]] constexpr SwizzleSource ConvertGreenRed(SwizzleSource value) { |
| 298 | const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); | 402 | switch (value) { |
| 299 | std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); | 403 | case SwizzleSource::G: |
| 300 | 404 | return SwizzleSource::R; | |
| 301 | FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, | 405 | default: |
| 302 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 406 | return value; |
| 303 | |||
| 304 | for (u32 level = 0; level < params.num_levels; ++level) { | ||
| 305 | const VkBufferImageCopy copy = GetBufferImageCopy(level); | ||
| 306 | if (image->GetAspectMask() == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | ||
| 307 | scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(), | ||
| 308 | copy](vk::CommandBuffer cmdbuf) { | ||
| 309 | std::array<VkBufferImageCopy, 2> copies = {copy, copy}; | ||
| 310 | copies[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 311 | copies[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; | ||
| 312 | cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 313 | copies); | ||
| 314 | }); | ||
| 315 | } else { | ||
| 316 | scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(), | ||
| 317 | copy](vk::CommandBuffer cmdbuf) { | ||
| 318 | cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); | ||
| 319 | }); | ||
| 320 | } | ||
| 321 | } | 407 | } |
| 322 | } | 408 | } |
| 323 | 409 | ||
| 324 | VkBufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { | 410 | void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image, |
| 325 | return { | 411 | VkImageAspectFlags aspect_mask, bool is_initialized, |
| 326 | .bufferOffset = params.GetHostMipmapLevelOffset(level, is_converted), | 412 | std::span<const VkBufferImageCopy> copies) { |
| 327 | .bufferRowLength = 0, | 413 | static constexpr VkAccessFlags ACCESS_FLAGS = VK_ACCESS_SHADER_WRITE_BIT | |
| 328 | .bufferImageHeight = 0, | 414 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| 329 | .imageSubresource = | 415 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; |
| 416 | const VkImageMemoryBarrier read_barrier{ | ||
| 417 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 418 | .pNext = nullptr, | ||
| 419 | .srcAccessMask = ACCESS_FLAGS, | ||
| 420 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 421 | .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 422 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 423 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 424 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 425 | .image = image, | ||
| 426 | .subresourceRange = | ||
| 330 | { | 427 | { |
| 331 | .aspectMask = image->GetAspectMask(), | 428 | .aspectMask = aspect_mask, |
| 332 | .mipLevel = level, | 429 | .baseMipLevel = 0, |
| 430 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 333 | .baseArrayLayer = 0, | 431 | .baseArrayLayer = 0, |
| 334 | .layerCount = static_cast<u32>(params.GetNumLayers()), | 432 | .layerCount = VK_REMAINING_ARRAY_LAYERS, |
| 335 | }, | 433 | }, |
| 336 | .imageOffset = {.x = 0, .y = 0, .z = 0}, | 434 | }; |
| 337 | .imageExtent = | 435 | const VkImageMemoryBarrier write_barrier{ |
| 436 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 437 | .pNext = nullptr, | ||
| 438 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 439 | .dstAccessMask = ACCESS_FLAGS, | ||
| 440 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 441 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 442 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 443 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 444 | .image = image, | ||
| 445 | .subresourceRange = | ||
| 338 | { | 446 | { |
| 339 | .width = params.GetMipWidth(level), | 447 | .aspectMask = aspect_mask, |
| 340 | .height = params.GetMipHeight(level), | 448 | .baseMipLevel = 0, |
| 341 | .depth = params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1U, | 449 | .levelCount = VK_REMAINING_MIP_LEVELS, |
| 450 | .baseArrayLayer = 0, | ||
| 451 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 342 | }, | 452 | }, |
| 343 | }; | 453 | }; |
| 454 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, | ||
| 455 | read_barrier); | ||
| 456 | cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies); | ||
| 457 | // TODO: Move this to another API | ||
| 458 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, | ||
| 459 | write_barrier); | ||
| 344 | } | 460 | } |
| 345 | 461 | ||
| 346 | VkImageSubresourceRange CachedSurface::GetImageSubresourceRange() const { | 462 | [[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region, |
| 347 | return {image->GetAspectMask(), 0, params.num_levels, 0, | 463 | const std::array<Offset2D, 2>& src_region, |
| 348 | static_cast<u32>(params.GetNumLayers())}; | 464 | const VkImageSubresourceLayers& dst_layers, |
| 465 | const VkImageSubresourceLayers& src_layers) { | ||
| 466 | return VkImageBlit{ | ||
| 467 | .srcSubresource = src_layers, | ||
| 468 | .srcOffsets = | ||
| 469 | { | ||
| 470 | { | ||
| 471 | .x = src_region[0].x, | ||
| 472 | .y = src_region[0].y, | ||
| 473 | .z = 0, | ||
| 474 | }, | ||
| 475 | { | ||
| 476 | .x = src_region[1].x, | ||
| 477 | .y = src_region[1].y, | ||
| 478 | .z = 1, | ||
| 479 | }, | ||
| 480 | }, | ||
| 481 | .dstSubresource = dst_layers, | ||
| 482 | .dstOffsets = | ||
| 483 | { | ||
| 484 | { | ||
| 485 | .x = dst_region[0].x, | ||
| 486 | .y = dst_region[0].y, | ||
| 487 | .z = 0, | ||
| 488 | }, | ||
| 489 | { | ||
| 490 | .x = dst_region[1].x, | ||
| 491 | .y = dst_region[1].y, | ||
| 492 | .z = 1, | ||
| 493 | }, | ||
| 494 | }, | ||
| 495 | }; | ||
| 349 | } | 496 | } |
| 350 | 497 | ||
| 351 | CachedSurfaceView::CachedSurfaceView(const VKDevice& device, CachedSurface& surface, | 498 | [[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region, |
| 352 | const ViewParams& params) | 499 | const std::array<Offset2D, 2>& src_region, |
| 353 | : VideoCommon::ViewBase{params}, params{surface.GetSurfaceParams()}, | 500 | const VkImageSubresourceLayers& dst_layers, |
| 354 | image{surface.GetImageHandle()}, buffer_view{surface.GetBufferViewHandle()}, | 501 | const VkImageSubresourceLayers& src_layers) { |
| 355 | aspect_mask{surface.GetAspectMask()}, device{device}, surface{surface}, | 502 | return VkImageResolve{ |
| 356 | base_level{params.base_level}, num_levels{params.num_levels}, | 503 | .srcSubresource = src_layers, |
| 357 | image_view_type{image ? GetImageViewType(params.target) : VK_IMAGE_VIEW_TYPE_1D} { | 504 | .srcOffset = |
| 358 | if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { | 505 | { |
| 359 | base_layer = 0; | 506 | .x = src_region[0].x, |
| 360 | num_layers = 1; | 507 | .y = src_region[0].y, |
| 361 | base_slice = params.base_layer; | 508 | .z = 0, |
| 362 | num_slices = params.num_layers; | 509 | }, |
| 363 | } else { | 510 | .dstSubresource = dst_layers, |
| 364 | base_layer = params.base_layer; | 511 | .dstOffset = |
| 365 | num_layers = params.num_layers; | 512 | { |
| 366 | } | 513 | .x = dst_region[0].x, |
| 514 | .y = dst_region[0].y, | ||
| 515 | .z = 0, | ||
| 516 | }, | ||
| 517 | .extent = | ||
| 518 | { | ||
| 519 | .width = static_cast<u32>(dst_region[1].x - dst_region[0].x), | ||
| 520 | .height = static_cast<u32>(dst_region[1].y - dst_region[0].y), | ||
| 521 | .depth = 1, | ||
| 522 | }, | ||
| 523 | }; | ||
| 367 | } | 524 | } |
| 368 | 525 | ||
| 369 | CachedSurfaceView::~CachedSurfaceView() = default; | 526 | struct RangedBarrierRange { |
| 370 | 527 | u32 min_mip = std::numeric_limits<u32>::max(); | |
| 371 | VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSource y_source, | 528 | u32 max_mip = std::numeric_limits<u32>::min(); |
| 372 | SwizzleSource z_source, SwizzleSource w_source) { | 529 | u32 min_layer = std::numeric_limits<u32>::max(); |
| 373 | const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); | 530 | u32 max_layer = std::numeric_limits<u32>::min(); |
| 374 | if (last_image_view && last_swizzle == new_swizzle) { | 531 | |
| 375 | return last_image_view; | 532 | void AddLayers(const VkImageSubresourceLayers& layers) { |
| 533 | min_mip = std::min(min_mip, layers.mipLevel); | ||
| 534 | max_mip = std::max(max_mip, layers.mipLevel + 1); | ||
| 535 | min_layer = std::min(min_layer, layers.baseArrayLayer); | ||
| 536 | max_layer = std::max(max_layer, layers.baseArrayLayer + layers.layerCount); | ||
| 376 | } | 537 | } |
| 377 | last_swizzle = new_swizzle; | ||
| 378 | 538 | ||
| 379 | const auto [entry, is_cache_miss] = view_cache.try_emplace(new_swizzle); | 539 | VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) const noexcept { |
| 380 | auto& image_view = entry->second; | 540 | return VkImageSubresourceRange{ |
| 381 | if (!is_cache_miss) { | 541 | .aspectMask = aspect_mask, |
| 382 | return last_image_view = *image_view; | 542 | .baseMipLevel = min_mip, |
| 543 | .levelCount = max_mip - min_mip, | ||
| 544 | .baseArrayLayer = min_layer, | ||
| 545 | .layerCount = max_layer - min_layer, | ||
| 546 | }; | ||
| 383 | } | 547 | } |
| 548 | }; | ||
| 384 | 549 | ||
| 385 | std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source), | 550 | } // Anonymous namespace |
| 386 | MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)}; | ||
| 387 | if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5_UNORM) { | ||
| 388 | // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here. | ||
| 389 | std::swap(swizzle[0], swizzle[2]); | ||
| 390 | } | ||
| 391 | 551 | ||
| 392 | // Games can sample depth or stencil values on textures. This is decided by the swizzle value on | 552 | void TextureCacheRuntime::Finish() { |
| 393 | // hardware. To emulate this on Vulkan we specify it in the aspect. | 553 | scheduler.Finish(); |
| 394 | VkImageAspectFlags aspect = aspect_mask; | 554 | } |
| 395 | if (aspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | ||
| 396 | UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G); | ||
| 397 | const bool is_first = x_source == SwizzleSource::R; | ||
| 398 | switch (params.pixel_format) { | ||
| 399 | case VideoCore::Surface::PixelFormat::D24_UNORM_S8_UINT: | ||
| 400 | case VideoCore::Surface::PixelFormat::D32_FLOAT_S8_UINT: | ||
| 401 | aspect = is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT; | ||
| 402 | break; | ||
| 403 | case VideoCore::Surface::PixelFormat::S8_UINT_D24_UNORM: | ||
| 404 | aspect = is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 405 | break; | ||
| 406 | default: | ||
| 407 | aspect = VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 408 | UNIMPLEMENTED(); | ||
| 409 | } | ||
| 410 | 555 | ||
| 411 | // Make sure we sample the first component | 556 | ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { |
| 412 | std::transform( | 557 | const auto& buffer = staging_buffer_pool.GetUnusedBuffer(size, true); |
| 413 | swizzle.begin(), swizzle.end(), swizzle.begin(), [](VkComponentSwizzle component) { | 558 | return ImageBufferMap{ |
| 414 | return component == VK_COMPONENT_SWIZZLE_G ? VK_COMPONENT_SWIZZLE_R : component; | 559 | .handle = *buffer.handle, |
| 415 | }); | 560 | .map = buffer.commit->Map(size), |
| 416 | } | 561 | }; |
| 562 | } | ||
| 417 | 563 | ||
| 418 | if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { | 564 | void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 419 | ASSERT(base_slice == 0); | 565 | const std::array<Offset2D, 2>& dst_region, |
| 420 | ASSERT(num_slices == params.depth); | 566 | const std::array<Offset2D, 2>& src_region, |
| 567 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 568 | Tegra::Engines::Fermi2D::Operation operation) { | ||
| 569 | const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format); | ||
| 570 | const bool is_dst_msaa = dst.Samples() != VK_SAMPLE_COUNT_1_BIT; | ||
| 571 | const bool is_src_msaa = src.Samples() != VK_SAMPLE_COUNT_1_BIT; | ||
| 572 | ASSERT(aspect_mask == ImageAspectMask(dst.format)); | ||
| 573 | if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) { | ||
| 574 | blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, filter, | ||
| 575 | operation); | ||
| 576 | return; | ||
| 421 | } | 577 | } |
| 422 | 578 | if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | |
| 423 | image_view = device.GetLogical().CreateImageView({ | 579 | if (!device.IsBlitDepthStencilSupported()) { |
| 424 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 580 | UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa); |
| 425 | .pNext = nullptr, | 581 | blit_image_helper.BlitDepthStencil(dst_framebuffer, src.DepthView(), src.StencilView(), |
| 426 | .flags = 0, | 582 | dst_region, src_region, filter, operation); |
| 427 | .image = surface.GetImageHandle(), | 583 | return; |
| 428 | .viewType = image_view_type, | 584 | } |
| 429 | .format = surface.GetImage().GetFormat(), | 585 | } |
| 430 | .components = | 586 | ASSERT(src.ImageFormat() == dst.ImageFormat()); |
| 431 | { | 587 | ASSERT(!(is_dst_msaa && !is_src_msaa)); |
| 432 | .r = swizzle[0], | 588 | ASSERT(operation == Fermi2D::Operation::SrcCopy); |
| 433 | .g = swizzle[1], | 589 | |
| 434 | .b = swizzle[2], | 590 | const VkImage dst_image = dst.ImageHandle(); |
| 435 | .a = swizzle[3], | 591 | const VkImage src_image = src.ImageHandle(); |
| 592 | const VkImageSubresourceLayers dst_layers = MakeSubresourceLayers(&dst); | ||
| 593 | const VkImageSubresourceLayers src_layers = MakeSubresourceLayers(&src); | ||
| 594 | const bool is_resolve = is_src_msaa && !is_dst_msaa; | ||
| 595 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 596 | scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers, | ||
| 597 | aspect_mask, is_resolve](vk::CommandBuffer cmdbuf) { | ||
| 598 | const std::array read_barriers{ | ||
| 599 | VkImageMemoryBarrier{ | ||
| 600 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 601 | .pNext = nullptr, | ||
| 602 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | | ||
| 603 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 604 | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 605 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 606 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 607 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 608 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 609 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 610 | .image = src_image, | ||
| 611 | .subresourceRange{ | ||
| 612 | .aspectMask = aspect_mask, | ||
| 613 | .baseMipLevel = 0, | ||
| 614 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 615 | .baseArrayLayer = 0, | ||
| 616 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 617 | }, | ||
| 436 | }, | 618 | }, |
| 437 | .subresourceRange = | 619 | VkImageMemoryBarrier{ |
| 438 | { | 620 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| 439 | .aspectMask = aspect, | 621 | .pNext = nullptr, |
| 440 | .baseMipLevel = base_level, | 622 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | |
| 441 | .levelCount = num_levels, | 623 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | |
| 442 | .baseArrayLayer = base_layer, | 624 | VK_ACCESS_TRANSFER_WRITE_BIT, |
| 443 | .layerCount = num_layers, | 625 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 626 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 627 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 628 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 629 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 630 | .image = dst_image, | ||
| 631 | .subresourceRange{ | ||
| 632 | .aspectMask = aspect_mask, | ||
| 633 | .baseMipLevel = 0, | ||
| 634 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 635 | .baseArrayLayer = 0, | ||
| 636 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 637 | }, | ||
| 638 | }, | ||
| 639 | }; | ||
| 640 | VkImageMemoryBarrier write_barrier{ | ||
| 641 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 642 | .pNext = nullptr, | ||
| 643 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 644 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | | ||
| 645 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 646 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 647 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 648 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 649 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 650 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 651 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 652 | .image = dst_image, | ||
| 653 | .subresourceRange{ | ||
| 654 | .aspectMask = aspect_mask, | ||
| 655 | .baseMipLevel = 0, | ||
| 656 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 657 | .baseArrayLayer = 0, | ||
| 658 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 444 | }, | 659 | }, |
| 660 | }; | ||
| 661 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 662 | 0, nullptr, nullptr, read_barriers); | ||
| 663 | if (is_resolve) { | ||
| 664 | cmdbuf.ResolveImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, | ||
| 665 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 666 | MakeImageResolve(dst_region, src_region, dst_layers, src_layers)); | ||
| 667 | } else { | ||
| 668 | const bool is_linear = filter == Fermi2D::Filter::Bilinear; | ||
| 669 | const VkFilter vk_filter = is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; | ||
| 670 | cmdbuf.BlitImage( | ||
| 671 | src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 672 | MakeImageBlit(dst_region, src_region, dst_layers, src_layers), vk_filter); | ||
| 673 | } | ||
| 674 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 675 | 0, write_barrier); | ||
| 445 | }); | 676 | }); |
| 446 | |||
| 447 | return last_image_view = *image_view; | ||
| 448 | } | 677 | } |
| 449 | 678 | ||
| 450 | VkImageView CachedSurfaceView::GetAttachment() { | 679 | void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) { |
| 451 | if (render_target) { | 680 | switch (dst_view.format) { |
| 452 | return *render_target; | 681 | case PixelFormat::R16_UNORM: |
| 682 | if (src_view.format == PixelFormat::D16_UNORM) { | ||
| 683 | return blit_image_helper.ConvertD16ToR16(dst, src_view); | ||
| 684 | } | ||
| 685 | break; | ||
| 686 | case PixelFormat::R32_FLOAT: | ||
| 687 | if (src_view.format == PixelFormat::D32_FLOAT) { | ||
| 688 | return blit_image_helper.ConvertD32ToR32(dst, src_view); | ||
| 689 | } | ||
| 690 | break; | ||
| 691 | case PixelFormat::D16_UNORM: | ||
| 692 | if (src_view.format == PixelFormat::R16_UNORM) { | ||
| 693 | return blit_image_helper.ConvertR16ToD16(dst, src_view); | ||
| 694 | } | ||
| 695 | break; | ||
| 696 | case PixelFormat::D32_FLOAT: | ||
| 697 | if (src_view.format == PixelFormat::R32_FLOAT) { | ||
| 698 | return blit_image_helper.ConvertR32ToD32(dst, src_view); | ||
| 699 | } | ||
| 700 | break; | ||
| 701 | default: | ||
| 702 | break; | ||
| 453 | } | 703 | } |
| 704 | UNIMPLEMENTED_MSG("Unimplemented format copy from {} to {}", src_view.format, dst_view.format); | ||
| 705 | } | ||
| 454 | 706 | ||
| 455 | VkImageViewCreateInfo ci{ | 707 | void TextureCacheRuntime::CopyImage(Image& dst, Image& src, |
| 456 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 708 | std::span<const VideoCommon::ImageCopy> copies) { |
| 457 | .pNext = nullptr, | 709 | std::vector<VkImageCopy> vk_copies(copies.size()); |
| 458 | .flags = 0, | 710 | const VkImageAspectFlags aspect_mask = dst.AspectMask(); |
| 459 | .image = surface.GetImageHandle(), | 711 | ASSERT(aspect_mask == src.AspectMask()); |
| 460 | .viewType = VK_IMAGE_VIEW_TYPE_1D, | 712 | |
| 461 | .format = surface.GetImage().GetFormat(), | 713 | std::ranges::transform(copies, vk_copies.begin(), [aspect_mask](const auto& copy) { |
| 462 | .components = | 714 | return MakeImageCopy(copy, aspect_mask); |
| 463 | { | 715 | }); |
| 464 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | 716 | const VkImage dst_image = dst.Handle(); |
| 465 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | 717 | const VkImage src_image = src.Handle(); |
| 466 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | 718 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 467 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | 719 | scheduler.Record([dst_image, src_image, aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { |
| 720 | RangedBarrierRange dst_range; | ||
| 721 | RangedBarrierRange src_range; | ||
| 722 | for (const VkImageCopy& copy : vk_copies) { | ||
| 723 | dst_range.AddLayers(copy.dstSubresource); | ||
| 724 | src_range.AddLayers(copy.srcSubresource); | ||
| 725 | } | ||
| 726 | const std::array read_barriers{ | ||
| 727 | VkImageMemoryBarrier{ | ||
| 728 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 729 | .pNext = nullptr, | ||
| 730 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 731 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 732 | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 733 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 734 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 735 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 736 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 737 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 738 | .image = src_image, | ||
| 739 | .subresourceRange = src_range.SubresourceRange(aspect_mask), | ||
| 468 | }, | 740 | }, |
| 469 | .subresourceRange = | 741 | VkImageMemoryBarrier{ |
| 470 | { | 742 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| 471 | .aspectMask = aspect_mask, | 743 | .pNext = nullptr, |
| 472 | .baseMipLevel = base_level, | 744 | .srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | |
| 473 | .levelCount = num_levels, | 745 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
| 474 | .baseArrayLayer = 0, | 746 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| 475 | .layerCount = 0, | 747 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
| 748 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 749 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 750 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 751 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 752 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 753 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 754 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 755 | .image = dst_image, | ||
| 756 | .subresourceRange = dst_range.SubresourceRange(aspect_mask), | ||
| 476 | }, | 757 | }, |
| 477 | }; | 758 | }; |
| 478 | if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { | 759 | const VkImageMemoryBarrier write_barrier{ |
| 479 | ci.viewType = num_slices > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; | 760 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| 480 | ci.subresourceRange.baseArrayLayer = base_slice; | 761 | .pNext = nullptr, |
| 481 | ci.subresourceRange.layerCount = num_slices; | 762 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 763 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | | ||
| 764 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | | ||
| 765 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 766 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 767 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 768 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 769 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 770 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 771 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 772 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 773 | .image = dst_image, | ||
| 774 | .subresourceRange = dst_range.SubresourceRange(aspect_mask), | ||
| 775 | }; | ||
| 776 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 777 | 0, {}, {}, read_barriers); | ||
| 778 | cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, | ||
| 779 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_copies); | ||
| 780 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 781 | 0, write_barrier); | ||
| 782 | }); | ||
| 783 | } | ||
| 784 | |||
| 785 | Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_addr_, | ||
| 786 | VAddr cpu_addr_) | ||
| 787 | : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime.scheduler}, | ||
| 788 | image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), | ||
| 789 | aspect_mask(ImageAspectMask(info.format)) { | ||
| 790 | if (image) { | ||
| 791 | commit = runtime.memory_manager.Commit(image, false); | ||
| 482 | } else { | 792 | } else { |
| 483 | ci.viewType = image_view_type; | 793 | commit = runtime.memory_manager.Commit(buffer, false); |
| 484 | ci.subresourceRange.baseArrayLayer = base_layer; | 794 | } |
| 485 | ci.subresourceRange.layerCount = num_layers; | 795 | if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { |
| 796 | flags |= VideoCommon::ImageFlagBits::Converted; | ||
| 797 | } | ||
| 798 | if (runtime.device.HasDebuggingToolAttached()) { | ||
| 799 | if (image) { | ||
| 800 | image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); | ||
| 801 | } else { | ||
| 802 | buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); | ||
| 803 | } | ||
| 486 | } | 804 | } |
| 487 | render_target = device.GetLogical().CreateImageView(ci); | ||
| 488 | return *render_target; | ||
| 489 | } | 805 | } |
| 490 | 806 | ||
| 491 | VKTextureCache::VKTextureCache(VideoCore::RasterizerInterface& rasterizer, | 807 | void Image::UploadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 492 | Tegra::Engines::Maxwell3D& maxwell3d, | 808 | std::span<const BufferImageCopy> copies) { |
| 493 | Tegra::MemoryManager& gpu_memory, const VKDevice& device_, | 809 | // TODO: Move this to another API |
| 494 | VKMemoryManager& memory_manager_, VKScheduler& scheduler_, | 810 | scheduler->RequestOutsideRenderPassOperationContext(); |
| 495 | VKStagingBufferPool& staging_pool_) | 811 | std::vector vk_copies = TransformBufferImageCopies(copies, buffer_offset, aspect_mask); |
| 496 | : TextureCache(rasterizer, maxwell3d, gpu_memory, device_.IsOptimalAstcSupported()), | 812 | const VkBuffer src_buffer = map.handle; |
| 497 | device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ | 813 | const VkImage vk_image = *image; |
| 498 | staging_pool_} {} | 814 | const VkImageAspectFlags vk_aspect_mask = aspect_mask; |
| 499 | 815 | const bool is_initialized = std::exchange(initialized, true); | |
| 500 | VKTextureCache::~VKTextureCache() = default; | 816 | scheduler->Record([src_buffer, vk_image, vk_aspect_mask, is_initialized, |
| 501 | 817 | vk_copies](vk::CommandBuffer cmdbuf) { | |
| 502 | Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { | 818 | CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, is_initialized, vk_copies); |
| 503 | return std::make_shared<CachedSurface>(device, memory_manager, scheduler, staging_pool, | 819 | }); |
| 504 | gpu_addr, params); | ||
| 505 | } | 820 | } |
| 506 | 821 | ||
| 507 | void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface, | 822 | void Image::UploadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 508 | const VideoCommon::CopyParams& copy_params) { | 823 | std::span<const VideoCommon::BufferCopy> copies) { |
| 509 | const bool src_3d = src_surface->GetSurfaceParams().target == SurfaceTarget::Texture3D; | 824 | // TODO: Move this to another API |
| 510 | const bool dst_3d = dst_surface->GetSurfaceParams().target == SurfaceTarget::Texture3D; | 825 | scheduler->RequestOutsideRenderPassOperationContext(); |
| 511 | UNIMPLEMENTED_IF(src_3d); | 826 | std::vector vk_copies = TransformBufferCopies(copies, buffer_offset); |
| 827 | const VkBuffer src_buffer = map.handle; | ||
| 828 | const VkBuffer dst_buffer = *buffer; | ||
| 829 | scheduler->Record([src_buffer, dst_buffer, vk_copies](vk::CommandBuffer cmdbuf) { | ||
| 830 | // TODO: Barriers | ||
| 831 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, vk_copies); | ||
| 832 | }); | ||
| 833 | } | ||
| 512 | 834 | ||
| 513 | // The texture cache handles depth in OpenGL terms, we have to handle it as subresource and | 835 | void Image::DownloadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 514 | // dimension respectively. | 836 | std::span<const BufferImageCopy> copies) { |
| 515 | const u32 dst_base_layer = dst_3d ? 0 : copy_params.dest_z; | 837 | std::vector vk_copies = TransformBufferImageCopies(copies, buffer_offset, aspect_mask); |
| 516 | const u32 dst_offset_z = dst_3d ? copy_params.dest_z : 0; | 838 | scheduler->Record([buffer = map.handle, image = *image, aspect_mask = aspect_mask, |
| 839 | vk_copies](vk::CommandBuffer cmdbuf) { | ||
| 840 | // TODO: Barriers | ||
| 841 | cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_GENERAL, buffer, vk_copies); | ||
| 842 | }); | ||
| 843 | } | ||
| 517 | 844 | ||
| 518 | const u32 extent_z = dst_3d ? copy_params.depth : 1; | 845 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, |
| 519 | const u32 num_layers = dst_3d ? 1 : copy_params.depth; | 846 | ImageId image_id_, Image& image) |
| 847 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device}, | ||
| 848 | image_handle{image.Handle()}, image_format{image.info.format}, samples{ConvertSampleCount( | ||
| 849 | image.info.num_samples)} { | ||
| 850 | const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); | ||
| 851 | std::array<SwizzleSource, 4> swizzle{ | ||
| 852 | SwizzleSource::R, | ||
| 853 | SwizzleSource::G, | ||
| 854 | SwizzleSource::B, | ||
| 855 | SwizzleSource::A, | ||
| 856 | }; | ||
| 857 | if (!info.IsRenderTarget()) { | ||
| 858 | swizzle = info.Swizzle(); | ||
| 859 | if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { | ||
| 860 | std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); | ||
| 861 | } | ||
| 862 | } | ||
| 863 | const VkFormat vk_format = | ||
| 864 | MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format; | ||
| 865 | const VkImageViewCreateInfo create_info{ | ||
| 866 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 867 | .pNext = nullptr, | ||
| 868 | .flags = 0, | ||
| 869 | .image = image.Handle(), | ||
| 870 | .viewType = VkImageViewType{}, | ||
| 871 | .format = vk_format, | ||
| 872 | .components{ | ||
| 873 | .r = ComponentSwizzle(swizzle[0]), | ||
| 874 | .g = ComponentSwizzle(swizzle[1]), | ||
| 875 | .b = ComponentSwizzle(swizzle[2]), | ||
| 876 | .a = ComponentSwizzle(swizzle[3]), | ||
| 877 | }, | ||
| 878 | .subresourceRange = MakeSubresourceRange(aspect_mask, info.range), | ||
| 879 | }; | ||
| 880 | const auto create = [&](VideoCommon::ImageViewType view_type, std::optional<u32> num_layers) { | ||
| 881 | VkImageViewCreateInfo ci{create_info}; | ||
| 882 | ci.viewType = ImageViewType(view_type); | ||
| 883 | if (num_layers) { | ||
| 884 | ci.subresourceRange.layerCount = *num_layers; | ||
| 885 | } | ||
| 886 | vk::ImageView handle = device->GetLogical().CreateImageView(ci); | ||
| 887 | if (device->HasDebuggingToolAttached()) { | ||
| 888 | handle.SetObjectNameEXT(VideoCommon::Name(*this, view_type).c_str()); | ||
| 889 | } | ||
| 890 | image_views[static_cast<size_t>(view_type)] = std::move(handle); | ||
| 891 | }; | ||
| 892 | switch (info.type) { | ||
| 893 | case VideoCommon::ImageViewType::e1D: | ||
| 894 | case VideoCommon::ImageViewType::e1DArray: | ||
| 895 | create(VideoCommon::ImageViewType::e1D, 1); | ||
| 896 | create(VideoCommon::ImageViewType::e1DArray, std::nullopt); | ||
| 897 | render_target = Handle(VideoCommon::ImageViewType::e1DArray); | ||
| 898 | break; | ||
| 899 | case VideoCommon::ImageViewType::e2D: | ||
| 900 | case VideoCommon::ImageViewType::e2DArray: | ||
| 901 | create(VideoCommon::ImageViewType::e2D, 1); | ||
| 902 | create(VideoCommon::ImageViewType::e2DArray, std::nullopt); | ||
| 903 | render_target = Handle(VideoCommon::ImageViewType::e2DArray); | ||
| 904 | break; | ||
| 905 | case VideoCommon::ImageViewType::e3D: | ||
| 906 | create(VideoCommon::ImageViewType::e3D, std::nullopt); | ||
| 907 | render_target = Handle(VideoCommon::ImageViewType::e3D); | ||
| 908 | break; | ||
| 909 | case VideoCommon::ImageViewType::Cube: | ||
| 910 | case VideoCommon::ImageViewType::CubeArray: | ||
| 911 | create(VideoCommon::ImageViewType::Cube, 6); | ||
| 912 | create(VideoCommon::ImageViewType::CubeArray, std::nullopt); | ||
| 913 | break; | ||
| 914 | case VideoCommon::ImageViewType::Rect: | ||
| 915 | UNIMPLEMENTED(); | ||
| 916 | break; | ||
| 917 | case VideoCommon::ImageViewType::Buffer: | ||
| 918 | buffer_view = device->GetLogical().CreateBufferView(VkBufferViewCreateInfo{ | ||
| 919 | .sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, | ||
| 920 | .pNext = nullptr, | ||
| 921 | .flags = 0, | ||
| 922 | .buffer = image.Buffer(), | ||
| 923 | .format = vk_format, | ||
| 924 | .offset = 0, // TODO: Redesign buffer cache to support this | ||
| 925 | .range = image.guest_size_bytes, | ||
| 926 | }); | ||
| 927 | break; | ||
| 928 | } | ||
| 929 | } | ||
| 520 | 930 | ||
| 521 | // We can't copy inside a renderpass | 931 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams& params) |
| 522 | scheduler.RequestOutsideRenderPassOperationContext(); | 932 | : VideoCommon::ImageViewBase{params} {} |
| 523 | 933 | ||
| 524 | src_surface->Transition(copy_params.source_z, copy_params.depth, copy_params.source_level, 1, | 934 | VkImageView ImageView::DepthView() { |
| 525 | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, | 935 | if (depth_view) { |
| 526 | VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); | 936 | return *depth_view; |
| 527 | dst_surface->Transition(dst_base_layer, num_layers, copy_params.dest_level, 1, | 937 | } |
| 528 | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, | 938 | depth_view = MakeDepthStencilView(VK_IMAGE_ASPECT_DEPTH_BIT); |
| 529 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 939 | return *depth_view; |
| 940 | } | ||
| 530 | 941 | ||
| 531 | const VkImageCopy copy{ | 942 | VkImageView ImageView::StencilView() { |
| 532 | .srcSubresource = | 943 | if (stencil_view) { |
| 533 | { | 944 | return *stencil_view; |
| 534 | .aspectMask = src_surface->GetAspectMask(), | 945 | } |
| 535 | .mipLevel = copy_params.source_level, | 946 | stencil_view = MakeDepthStencilView(VK_IMAGE_ASPECT_STENCIL_BIT); |
| 536 | .baseArrayLayer = copy_params.source_z, | 947 | return *stencil_view; |
| 537 | .layerCount = num_layers, | 948 | } |
| 538 | }, | ||
| 539 | .srcOffset = | ||
| 540 | { | ||
| 541 | .x = static_cast<s32>(copy_params.source_x), | ||
| 542 | .y = static_cast<s32>(copy_params.source_y), | ||
| 543 | .z = 0, | ||
| 544 | }, | ||
| 545 | .dstSubresource = | ||
| 546 | { | ||
| 547 | .aspectMask = dst_surface->GetAspectMask(), | ||
| 548 | .mipLevel = copy_params.dest_level, | ||
| 549 | .baseArrayLayer = dst_base_layer, | ||
| 550 | .layerCount = num_layers, | ||
| 551 | }, | ||
| 552 | .dstOffset = | ||
| 553 | { | ||
| 554 | .x = static_cast<s32>(copy_params.dest_x), | ||
| 555 | .y = static_cast<s32>(copy_params.dest_y), | ||
| 556 | .z = static_cast<s32>(dst_offset_z), | ||
| 557 | }, | ||
| 558 | .extent = | ||
| 559 | { | ||
| 560 | .width = copy_params.width, | ||
| 561 | .height = copy_params.height, | ||
| 562 | .depth = extent_z, | ||
| 563 | }, | ||
| 564 | }; | ||
| 565 | 949 | ||
| 566 | const VkImage src_image = src_surface->GetImageHandle(); | 950 | vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) { |
| 567 | const VkImage dst_image = dst_surface->GetImageHandle(); | 951 | return device->GetLogical().CreateImageView({ |
| 568 | scheduler.Record([src_image, dst_image, copy](vk::CommandBuffer cmdbuf) { | 952 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 569 | cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, | 953 | .pNext = nullptr, |
| 570 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); | 954 | .flags = 0, |
| 955 | .image = image_handle, | ||
| 956 | .viewType = ImageViewType(type), | ||
| 957 | .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format, | ||
| 958 | .components{ | ||
| 959 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 960 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 961 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 962 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 963 | }, | ||
| 964 | .subresourceRange = MakeSubresourceRange(aspect_mask, range), | ||
| 571 | }); | 965 | }); |
| 572 | } | 966 | } |
| 573 | 967 | ||
| 574 | void VKTextureCache::ImageBlit(View& src_view, View& dst_view, | 968 | Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) { |
| 575 | const Tegra::Engines::Fermi2D::Config& copy_config) { | 969 | const auto& device = runtime.device; |
| 576 | // We can't blit inside a renderpass | 970 | const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported(); |
| 577 | scheduler.RequestOutsideRenderPassOperationContext(); | 971 | const std::array<float, 4> color = tsc.BorderColor(); |
| 578 | 972 | // C++20 bit_cast | |
| 579 | src_view->Transition(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, | 973 | VkClearColorValue border_color; |
| 580 | VK_ACCESS_TRANSFER_READ_BIT); | 974 | std::memcpy(&border_color, &color, sizeof(color)); |
| 581 | dst_view->Transition(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, | 975 | const VkSamplerCustomBorderColorCreateInfoEXT border_ci{ |
| 582 | VK_ACCESS_TRANSFER_WRITE_BIT); | 976 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT, |
| 583 | 977 | .pNext = nullptr, | |
| 584 | VkImageBlit blit; | 978 | .customBorderColor = border_color, |
| 585 | blit.srcSubresource = src_view->GetImageSubresourceLayers(); | 979 | .format = VK_FORMAT_UNDEFINED, |
| 586 | blit.srcOffsets[0].x = copy_config.src_rect.left; | 980 | }; |
| 587 | blit.srcOffsets[0].y = copy_config.src_rect.top; | 981 | const void* pnext = nullptr; |
| 588 | blit.srcOffsets[0].z = 0; | 982 | if (arbitrary_borders) { |
| 589 | blit.srcOffsets[1].x = copy_config.src_rect.right; | 983 | pnext = &border_ci; |
| 590 | blit.srcOffsets[1].y = copy_config.src_rect.bottom; | 984 | } |
| 591 | blit.srcOffsets[1].z = 1; | 985 | const VkSamplerReductionModeCreateInfoEXT reduction_ci{ |
| 592 | blit.dstSubresource = dst_view->GetImageSubresourceLayers(); | 986 | .sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT, |
| 593 | blit.dstOffsets[0].x = copy_config.dst_rect.left; | 987 | .pNext = pnext, |
| 594 | blit.dstOffsets[0].y = copy_config.dst_rect.top; | 988 | .reductionMode = MaxwellToVK::SamplerReduction(tsc.reduction_filter), |
| 595 | blit.dstOffsets[0].z = 0; | 989 | }; |
| 596 | blit.dstOffsets[1].x = copy_config.dst_rect.right; | 990 | if (runtime.device.IsExtSamplerFilterMinmaxSupported()) { |
| 597 | blit.dstOffsets[1].y = copy_config.dst_rect.bottom; | 991 | pnext = &reduction_ci; |
| 598 | blit.dstOffsets[1].z = 1; | 992 | } else if (reduction_ci.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT) { |
| 599 | 993 | LOG_WARNING(Render_Vulkan, "VK_EXT_sampler_filter_minmax is required"); | |
| 600 | const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear; | 994 | } |
| 601 | 995 | // Some games have samplers with garbage. Sanitize them here. | |
| 602 | scheduler.Record([src_image = src_view->GetImage(), dst_image = dst_view->GetImage(), blit, | 996 | const float max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f); |
| 603 | is_linear](vk::CommandBuffer cmdbuf) { | 997 | sampler = device.GetLogical().CreateSampler(VkSamplerCreateInfo{ |
| 604 | cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, | 998 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, |
| 605 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, blit, | 999 | .pNext = pnext, |
| 606 | is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); | 1000 | .flags = 0, |
| 1001 | .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter), | ||
| 1002 | .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter), | ||
| 1003 | .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter), | ||
| 1004 | .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter), | ||
| 1005 | .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter), | ||
| 1006 | .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter), | ||
| 1007 | .mipLodBias = tsc.LodBias(), | ||
| 1008 | .anisotropyEnable = static_cast<VkBool32>(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE), | ||
| 1009 | .maxAnisotropy = max_anisotropy, | ||
| 1010 | .compareEnable = tsc.depth_compare_enabled, | ||
| 1011 | .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), | ||
| 1012 | .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), | ||
| 1013 | .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(), | ||
| 1014 | .borderColor = | ||
| 1015 | arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color), | ||
| 1016 | .unnormalizedCoordinates = VK_FALSE, | ||
| 607 | }); | 1017 | }); |
| 608 | } | 1018 | } |
| 609 | 1019 | ||
| 610 | void VKTextureCache::BufferCopy(Surface& src_surface, Surface& dst_surface) { | 1020 | Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers, |
| 611 | // Currently unimplemented. PBO copies should be dropped and we should use a render pass to | 1021 | ImageView* depth_buffer, const VideoCommon::RenderTargets& key) { |
| 612 | // convert from color to depth and viceversa. | 1022 | std::vector<VkAttachmentDescription> descriptions; |
| 613 | LOG_WARNING(Render_Vulkan, "Unimplemented"); | 1023 | std::vector<VkImageView> attachments; |
| 1024 | RenderPassKey renderpass_key{}; | ||
| 1025 | s32 num_layers = 1; | ||
| 1026 | |||
| 1027 | for (size_t index = 0; index < NUM_RT; ++index) { | ||
| 1028 | const ImageView* const color_buffer = color_buffers[index]; | ||
| 1029 | if (!color_buffer) { | ||
| 1030 | renderpass_key.color_formats[index] = PixelFormat::Invalid; | ||
| 1031 | continue; | ||
| 1032 | } | ||
| 1033 | descriptions.push_back(AttachmentDescription(runtime.device, color_buffer)); | ||
| 1034 | attachments.push_back(color_buffer->RenderTarget()); | ||
| 1035 | renderpass_key.color_formats[index] = color_buffer->format; | ||
| 1036 | num_layers = std::max(num_layers, color_buffer->range.extent.layers); | ||
| 1037 | images[num_images] = color_buffer->ImageHandle(); | ||
| 1038 | image_ranges[num_images] = MakeSubresourceRange(color_buffer); | ||
| 1039 | samples = color_buffer->Samples(); | ||
| 1040 | ++num_images; | ||
| 1041 | } | ||
| 1042 | const size_t num_colors = attachments.size(); | ||
| 1043 | const VkAttachmentReference* depth_attachment = | ||
| 1044 | depth_buffer ? &ATTACHMENT_REFERENCES[num_colors] : nullptr; | ||
| 1045 | if (depth_buffer) { | ||
| 1046 | descriptions.push_back(AttachmentDescription(runtime.device, depth_buffer)); | ||
| 1047 | attachments.push_back(depth_buffer->RenderTarget()); | ||
| 1048 | renderpass_key.depth_format = depth_buffer->format; | ||
| 1049 | num_layers = std::max(num_layers, depth_buffer->range.extent.layers); | ||
| 1050 | images[num_images] = depth_buffer->ImageHandle(); | ||
| 1051 | image_ranges[num_images] = MakeSubresourceRange(depth_buffer); | ||
| 1052 | samples = depth_buffer->Samples(); | ||
| 1053 | ++num_images; | ||
| 1054 | } else { | ||
| 1055 | renderpass_key.depth_format = PixelFormat::Invalid; | ||
| 1056 | } | ||
| 1057 | renderpass_key.samples = samples; | ||
| 1058 | |||
| 1059 | const auto& device = runtime.device.GetLogical(); | ||
| 1060 | const auto [cache_pair, is_new] = runtime.renderpass_cache.try_emplace(renderpass_key); | ||
| 1061 | if (is_new) { | ||
| 1062 | const VkSubpassDescription subpass{ | ||
| 1063 | .flags = 0, | ||
| 1064 | .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 1065 | .inputAttachmentCount = 0, | ||
| 1066 | .pInputAttachments = nullptr, | ||
| 1067 | .colorAttachmentCount = static_cast<u32>(num_colors), | ||
| 1068 | .pColorAttachments = num_colors != 0 ? ATTACHMENT_REFERENCES.data() : nullptr, | ||
| 1069 | .pResolveAttachments = nullptr, | ||
| 1070 | .pDepthStencilAttachment = depth_attachment, | ||
| 1071 | .preserveAttachmentCount = 0, | ||
| 1072 | .pPreserveAttachments = nullptr, | ||
| 1073 | }; | ||
| 1074 | cache_pair->second = device.CreateRenderPass(VkRenderPassCreateInfo{ | ||
| 1075 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | ||
| 1076 | .pNext = nullptr, | ||
| 1077 | .flags = 0, | ||
| 1078 | .attachmentCount = static_cast<u32>(descriptions.size()), | ||
| 1079 | .pAttachments = descriptions.data(), | ||
| 1080 | .subpassCount = 1, | ||
| 1081 | .pSubpasses = &subpass, | ||
| 1082 | .dependencyCount = 0, | ||
| 1083 | .pDependencies = nullptr, | ||
| 1084 | }); | ||
| 1085 | } | ||
| 1086 | renderpass = *cache_pair->second; | ||
| 1087 | render_area = VkExtent2D{ | ||
| 1088 | .width = key.size.width, | ||
| 1089 | .height = key.size.height, | ||
| 1090 | }; | ||
| 1091 | num_color_buffers = static_cast<u32>(num_colors); | ||
| 1092 | framebuffer = device.CreateFramebuffer(VkFramebufferCreateInfo{ | ||
| 1093 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | ||
| 1094 | .pNext = nullptr, | ||
| 1095 | .flags = 0, | ||
| 1096 | .renderPass = renderpass, | ||
| 1097 | .attachmentCount = static_cast<u32>(attachments.size()), | ||
| 1098 | .pAttachments = attachments.data(), | ||
| 1099 | .width = key.size.width, | ||
| 1100 | .height = key.size.height, | ||
| 1101 | .layers = static_cast<u32>(num_layers), | ||
| 1102 | }); | ||
| 1103 | if (runtime.device.HasDebuggingToolAttached()) { | ||
| 1104 | framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str()); | ||
| 1105 | } | ||
| 614 | } | 1106 | } |
| 615 | 1107 | ||
| 616 | } // namespace Vulkan | 1108 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 39202feba..92a7aad8b 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -4,216 +4,270 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <compare> |
| 8 | #include <unordered_map> | 8 | #include <span> |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_image.h" | ||
| 12 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 10 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 15 | #include "video_core/texture_cache/surface_base.h" | ||
| 16 | #include "video_core/texture_cache/texture_cache.h" | 11 | #include "video_core/texture_cache/texture_cache.h" |
| 17 | 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | |
| 18 | namespace VideoCore { | ||
| 19 | class RasterizerInterface; | ||
| 20 | } | ||
| 21 | 13 | ||
| 22 | namespace Vulkan { | 14 | namespace Vulkan { |
| 23 | 15 | ||
| 24 | class RasterizerVulkan; | 16 | using VideoCommon::ImageId; |
| 25 | class VKDevice; | 17 | using VideoCommon::NUM_RT; |
| 18 | using VideoCommon::Offset2D; | ||
| 19 | using VideoCommon::RenderTargets; | ||
| 20 | using VideoCore::Surface::PixelFormat; | ||
| 21 | |||
| 26 | class VKScheduler; | 22 | class VKScheduler; |
| 27 | class VKStagingBufferPool; | 23 | class VKStagingBufferPool; |
| 28 | 24 | ||
| 29 | class CachedSurfaceView; | 25 | class BlitImageHelper; |
| 30 | class CachedSurface; | 26 | class Device; |
| 27 | class Image; | ||
| 28 | class ImageView; | ||
| 29 | class Framebuffer; | ||
| 31 | 30 | ||
| 32 | using Surface = std::shared_ptr<CachedSurface>; | 31 | struct RenderPassKey { |
| 33 | using View = std::shared_ptr<CachedSurfaceView>; | 32 | constexpr auto operator<=>(const RenderPassKey&) const noexcept = default; |
| 34 | using TextureCacheBase = VideoCommon::TextureCache<Surface, View>; | ||
| 35 | 33 | ||
| 36 | using VideoCommon::SurfaceParams; | 34 | std::array<PixelFormat, NUM_RT> color_formats; |
| 37 | using VideoCommon::ViewParams; | 35 | PixelFormat depth_format; |
| 36 | VkSampleCountFlagBits samples; | ||
| 37 | }; | ||
| 38 | 38 | ||
| 39 | class CachedSurface final : public VideoCommon::SurfaceBase<View> { | 39 | } // namespace Vulkan |
| 40 | friend CachedSurfaceView; | ||
| 41 | 40 | ||
| 42 | public: | 41 | namespace std { |
| 43 | explicit CachedSurface(const VKDevice& device, VKMemoryManager& memory_manager, | 42 | template <> |
| 44 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool, | 43 | struct hash<Vulkan::RenderPassKey> { |
| 45 | GPUVAddr gpu_addr, const SurfaceParams& params); | 44 | [[nodiscard]] constexpr size_t operator()(const Vulkan::RenderPassKey& key) const noexcept { |
| 46 | ~CachedSurface(); | 45 | size_t value = static_cast<size_t>(key.depth_format) << 48; |
| 46 | value ^= static_cast<size_t>(key.samples) << 52; | ||
| 47 | for (size_t i = 0; i < key.color_formats.size(); ++i) { | ||
| 48 | value ^= static_cast<size_t>(key.color_formats[i]) << (i * 6); | ||
| 49 | } | ||
| 50 | return value; | ||
| 51 | } | ||
| 52 | }; | ||
| 53 | } // namespace std | ||
| 47 | 54 | ||
| 48 | void UploadTexture(const std::vector<u8>& staging_buffer) override; | 55 | namespace Vulkan { |
| 49 | void DownloadTexture(std::vector<u8>& staging_buffer) override; | ||
| 50 | 56 | ||
| 51 | void FullTransition(VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access, | 57 | struct ImageBufferMap { |
| 52 | VkImageLayout new_layout) { | 58 | [[nodiscard]] VkBuffer Handle() const noexcept { |
| 53 | image->Transition(0, static_cast<u32>(params.GetNumLayers()), 0, params.num_levels, | 59 | return handle; |
| 54 | new_stage_mask, new_access, new_layout); | ||
| 55 | } | 60 | } |
| 56 | 61 | ||
| 57 | void Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | 62 | [[nodiscard]] std::span<u8> Span() const noexcept { |
| 58 | VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access, | 63 | return map.Span(); |
| 59 | VkImageLayout new_layout) { | ||
| 60 | image->Transition(base_layer, num_layers, base_level, num_levels, new_stage_mask, | ||
| 61 | new_access, new_layout); | ||
| 62 | } | 64 | } |
| 63 | 65 | ||
| 64 | VKImage& GetImage() { | 66 | VkBuffer handle; |
| 65 | return *image; | 67 | MemoryMap map; |
| 66 | } | 68 | }; |
| 67 | 69 | ||
| 68 | const VKImage& GetImage() const { | 70 | struct TextureCacheRuntime { |
| 69 | return *image; | 71 | const Device& device; |
| 72 | VKScheduler& scheduler; | ||
| 73 | VKMemoryManager& memory_manager; | ||
| 74 | VKStagingBufferPool& staging_buffer_pool; | ||
| 75 | BlitImageHelper& blit_image_helper; | ||
| 76 | std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache; | ||
| 77 | |||
| 78 | void Finish(); | ||
| 79 | |||
| 80 | [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size); | ||
| 81 | |||
| 82 | [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size) { | ||
| 83 | // TODO: Have a special function for this | ||
| 84 | return MapUploadBuffer(size); | ||
| 70 | } | 85 | } |
| 71 | 86 | ||
| 72 | VkImage GetImageHandle() const { | 87 | void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 73 | return *image->GetHandle(); | 88 | const std::array<Offset2D, 2>& dst_region, |
| 89 | const std::array<Offset2D, 2>& src_region, | ||
| 90 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 91 | Tegra::Engines::Fermi2D::Operation operation); | ||
| 92 | |||
| 93 | void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | ||
| 94 | |||
| 95 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view); | ||
| 96 | |||
| 97 | [[nodiscard]] bool CanAccelerateImageUpload(Image&) const noexcept { | ||
| 98 | return false; | ||
| 74 | } | 99 | } |
| 75 | 100 | ||
| 76 | VkImageAspectFlags GetAspectMask() const { | 101 | void AccelerateImageUpload(Image&, const ImageBufferMap&, size_t, |
| 77 | return image->GetAspectMask(); | 102 | std::span<const VideoCommon::SwizzleParameters>) { |
| 103 | UNREACHABLE(); | ||
| 78 | } | 104 | } |
| 79 | 105 | ||
| 80 | VkBufferView GetBufferViewHandle() const { | 106 | void InsertUploadMemoryBarrier() {} |
| 81 | return *buffer_view; | 107 | |
| 108 | bool HasBrokenTextureViewFormats() const noexcept { | ||
| 109 | // No known Vulkan driver has broken image views | ||
| 110 | return false; | ||
| 82 | } | 111 | } |
| 112 | }; | ||
| 83 | 113 | ||
| 84 | protected: | 114 | class Image : public VideoCommon::ImageBase { |
| 85 | void DecorateSurfaceName(); | 115 | public: |
| 116 | explicit Image(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, GPUVAddr gpu_addr, | ||
| 117 | VAddr cpu_addr); | ||
| 86 | 118 | ||
| 87 | View CreateView(const ViewParams& params) override; | 119 | void UploadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 120 | std::span<const VideoCommon::BufferImageCopy> copies); | ||
| 88 | 121 | ||
| 89 | private: | 122 | void UploadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 90 | void UploadBuffer(const std::vector<u8>& staging_buffer); | 123 | std::span<const VideoCommon::BufferCopy> copies); |
| 91 | 124 | ||
| 92 | void UploadImage(const std::vector<u8>& staging_buffer); | 125 | void DownloadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 126 | std::span<const VideoCommon::BufferImageCopy> copies); | ||
| 93 | 127 | ||
| 94 | VkBufferImageCopy GetBufferImageCopy(u32 level) const; | 128 | [[nodiscard]] VkImage Handle() const noexcept { |
| 129 | return *image; | ||
| 130 | } | ||
| 95 | 131 | ||
| 96 | VkImageSubresourceRange GetImageSubresourceRange() const; | 132 | [[nodiscard]] VkBuffer Buffer() const noexcept { |
| 133 | return *buffer; | ||
| 134 | } | ||
| 97 | 135 | ||
| 98 | const VKDevice& device; | 136 | [[nodiscard]] VkImageCreateFlags AspectMask() const noexcept { |
| 99 | VKMemoryManager& memory_manager; | 137 | return aspect_mask; |
| 100 | VKScheduler& scheduler; | 138 | } |
| 101 | VKStagingBufferPool& staging_pool; | ||
| 102 | 139 | ||
| 103 | std::optional<VKImage> image; | 140 | private: |
| 141 | VKScheduler* scheduler; | ||
| 142 | vk::Image image; | ||
| 104 | vk::Buffer buffer; | 143 | vk::Buffer buffer; |
| 105 | vk::BufferView buffer_view; | ||
| 106 | VKMemoryCommit commit; | 144 | VKMemoryCommit commit; |
| 107 | 145 | VkImageAspectFlags aspect_mask = 0; | |
| 108 | VkFormat format = VK_FORMAT_UNDEFINED; | 146 | bool initialized = false; |
| 109 | }; | 147 | }; |
| 110 | 148 | ||
| 111 | class CachedSurfaceView final : public VideoCommon::ViewBase { | 149 | class ImageView : public VideoCommon::ImageViewBase { |
| 112 | public: | 150 | public: |
| 113 | explicit CachedSurfaceView(const VKDevice& device, CachedSurface& surface, | 151 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); |
| 114 | const ViewParams& params); | 152 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams&); |
| 115 | ~CachedSurfaceView(); | ||
| 116 | 153 | ||
| 117 | VkImageView GetImageView(Tegra::Texture::SwizzleSource x_source, | 154 | [[nodiscard]] VkImageView DepthView(); |
| 118 | Tegra::Texture::SwizzleSource y_source, | ||
| 119 | Tegra::Texture::SwizzleSource z_source, | ||
| 120 | Tegra::Texture::SwizzleSource w_source); | ||
| 121 | 155 | ||
| 122 | VkImageView GetAttachment(); | 156 | [[nodiscard]] VkImageView StencilView(); |
| 123 | 157 | ||
| 124 | bool IsSameSurface(const CachedSurfaceView& rhs) const { | 158 | [[nodiscard]] VkImageView Handle(VideoCommon::ImageViewType query_type) const noexcept { |
| 125 | return &surface == &rhs.surface; | 159 | return *image_views[static_cast<size_t>(query_type)]; |
| 126 | } | 160 | } |
| 127 | 161 | ||
| 128 | u32 GetWidth() const { | 162 | [[nodiscard]] VkBufferView BufferView() const noexcept { |
| 129 | return params.GetMipWidth(base_level); | 163 | return *buffer_view; |
| 130 | } | 164 | } |
| 131 | 165 | ||
| 132 | u32 GetHeight() const { | 166 | [[nodiscard]] VkImage ImageHandle() const noexcept { |
| 133 | return params.GetMipHeight(base_level); | 167 | return image_handle; |
| 134 | } | 168 | } |
| 135 | 169 | ||
| 136 | u32 GetNumLayers() const { | 170 | [[nodiscard]] VkImageView RenderTarget() const noexcept { |
| 137 | return num_layers; | 171 | return render_target; |
| 138 | } | 172 | } |
| 139 | 173 | ||
| 140 | bool IsBufferView() const { | 174 | [[nodiscard]] PixelFormat ImageFormat() const noexcept { |
| 141 | return buffer_view; | 175 | return image_format; |
| 142 | } | 176 | } |
| 143 | 177 | ||
| 144 | VkImage GetImage() const { | 178 | [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept { |
| 145 | return image; | 179 | return samples; |
| 146 | } | 180 | } |
| 147 | 181 | ||
| 148 | VkBufferView GetBufferView() const { | 182 | private: |
| 149 | return buffer_view; | 183 | [[nodiscard]] vk::ImageView MakeDepthStencilView(VkImageAspectFlags aspect_mask); |
| 150 | } | ||
| 151 | 184 | ||
| 152 | VkImageSubresourceRange GetImageSubresourceRange() const { | 185 | const Device* device = nullptr; |
| 153 | return {aspect_mask, base_level, num_levels, base_layer, num_layers}; | 186 | std::array<vk::ImageView, VideoCommon::NUM_IMAGE_VIEW_TYPES> image_views; |
| 154 | } | 187 | vk::ImageView depth_view; |
| 188 | vk::ImageView stencil_view; | ||
| 189 | vk::BufferView buffer_view; | ||
| 190 | VkImage image_handle = VK_NULL_HANDLE; | ||
| 191 | VkImageView render_target = VK_NULL_HANDLE; | ||
| 192 | PixelFormat image_format = PixelFormat::Invalid; | ||
| 193 | VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; | ||
| 194 | }; | ||
| 155 | 195 | ||
| 156 | VkImageSubresourceLayers GetImageSubresourceLayers() const { | 196 | class ImageAlloc : public VideoCommon::ImageAllocBase {}; |
| 157 | return {surface.GetAspectMask(), base_level, base_layer, num_layers}; | ||
| 158 | } | ||
| 159 | 197 | ||
| 160 | void Transition(VkImageLayout new_layout, VkPipelineStageFlags new_stage_mask, | 198 | class Sampler { |
| 161 | VkAccessFlags new_access) const { | 199 | public: |
| 162 | surface.Transition(base_layer, num_layers, base_level, num_levels, new_stage_mask, | 200 | explicit Sampler(TextureCacheRuntime&, const Tegra::Texture::TSCEntry&); |
| 163 | new_access, new_layout); | ||
| 164 | } | ||
| 165 | 201 | ||
| 166 | void MarkAsModified(u64 tick) { | 202 | [[nodiscard]] VkSampler Handle() const noexcept { |
| 167 | surface.MarkAsModified(true, tick); | 203 | return *sampler; |
| 168 | } | 204 | } |
| 169 | 205 | ||
| 170 | private: | 206 | private: |
| 171 | // Store a copy of these values to avoid double dereference when reading them | 207 | vk::Sampler sampler; |
| 172 | const SurfaceParams params; | ||
| 173 | const VkImage image; | ||
| 174 | const VkBufferView buffer_view; | ||
| 175 | const VkImageAspectFlags aspect_mask; | ||
| 176 | |||
| 177 | const VKDevice& device; | ||
| 178 | CachedSurface& surface; | ||
| 179 | const u32 base_level; | ||
| 180 | const u32 num_levels; | ||
| 181 | const VkImageViewType image_view_type; | ||
| 182 | u32 base_layer = 0; | ||
| 183 | u32 num_layers = 0; | ||
| 184 | u32 base_slice = 0; | ||
| 185 | u32 num_slices = 0; | ||
| 186 | |||
| 187 | VkImageView last_image_view = nullptr; | ||
| 188 | u32 last_swizzle = 0; | ||
| 189 | |||
| 190 | vk::ImageView render_target; | ||
| 191 | std::unordered_map<u32, vk::ImageView> view_cache; | ||
| 192 | }; | 208 | }; |
| 193 | 209 | ||
| 194 | class VKTextureCache final : public TextureCacheBase { | 210 | class Framebuffer { |
| 195 | public: | 211 | public: |
| 196 | explicit VKTextureCache(VideoCore::RasterizerInterface& rasterizer, | 212 | explicit Framebuffer(TextureCacheRuntime&, std::span<ImageView*, NUM_RT> color_buffers, |
| 197 | Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, | 213 | ImageView* depth_buffer, const VideoCommon::RenderTargets& key); |
| 198 | const VKDevice& device, VKMemoryManager& memory_manager, | ||
| 199 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool); | ||
| 200 | ~VKTextureCache(); | ||
| 201 | 214 | ||
| 202 | private: | 215 | [[nodiscard]] VkFramebuffer Handle() const noexcept { |
| 203 | Surface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) override; | 216 | return *framebuffer; |
| 217 | } | ||
| 204 | 218 | ||
| 205 | void ImageCopy(Surface& src_surface, Surface& dst_surface, | 219 | [[nodiscard]] VkRenderPass RenderPass() const noexcept { |
| 206 | const VideoCommon::CopyParams& copy_params) override; | 220 | return renderpass; |
| 221 | } | ||
| 207 | 222 | ||
| 208 | void ImageBlit(View& src_view, View& dst_view, | 223 | [[nodiscard]] VkExtent2D RenderArea() const noexcept { |
| 209 | const Tegra::Engines::Fermi2D::Config& copy_config) override; | 224 | return render_area; |
| 225 | } | ||
| 210 | 226 | ||
| 211 | void BufferCopy(Surface& src_surface, Surface& dst_surface) override; | 227 | [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept { |
| 228 | return samples; | ||
| 229 | } | ||
| 212 | 230 | ||
| 213 | const VKDevice& device; | 231 | [[nodiscard]] u32 NumColorBuffers() const noexcept { |
| 214 | VKMemoryManager& memory_manager; | 232 | return num_color_buffers; |
| 215 | VKScheduler& scheduler; | 233 | } |
| 216 | VKStagingBufferPool& staging_pool; | 234 | |
| 235 | [[nodiscard]] u32 NumImages() const noexcept { | ||
| 236 | return num_images; | ||
| 237 | } | ||
| 238 | |||
| 239 | [[nodiscard]] const std::array<VkImage, 9>& Images() const noexcept { | ||
| 240 | return images; | ||
| 241 | } | ||
| 242 | |||
| 243 | [[nodiscard]] const std::array<VkImageSubresourceRange, 9>& ImageRanges() const noexcept { | ||
| 244 | return image_ranges; | ||
| 245 | } | ||
| 246 | |||
| 247 | private: | ||
| 248 | vk::Framebuffer framebuffer; | ||
| 249 | VkRenderPass renderpass{}; | ||
| 250 | VkExtent2D render_area{}; | ||
| 251 | VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; | ||
| 252 | u32 num_color_buffers = 0; | ||
| 253 | u32 num_images = 0; | ||
| 254 | std::array<VkImage, 9> images{}; | ||
| 255 | std::array<VkImageSubresourceRange, 9> image_ranges{}; | ||
| 217 | }; | 256 | }; |
| 218 | 257 | ||
| 258 | struct TextureCacheParams { | ||
| 259 | static constexpr bool ENABLE_VALIDATION = true; | ||
| 260 | static constexpr bool FRAMEBUFFER_BLITS = false; | ||
| 261 | static constexpr bool HAS_EMULATED_COPIES = false; | ||
| 262 | |||
| 263 | using Runtime = Vulkan::TextureCacheRuntime; | ||
| 264 | using Image = Vulkan::Image; | ||
| 265 | using ImageAlloc = Vulkan::ImageAlloc; | ||
| 266 | using ImageView = Vulkan::ImageView; | ||
| 267 | using Sampler = Vulkan::Sampler; | ||
| 268 | using Framebuffer = Vulkan::Framebuffer; | ||
| 269 | }; | ||
| 270 | |||
| 271 | using TextureCache = VideoCommon::TextureCache<TextureCacheParams>; | ||
| 272 | |||
| 219 | } // namespace Vulkan | 273 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp index 351c048d2..f99273c6a 100644 --- a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp | |||
| @@ -7,15 +7,15 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 10 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 12 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 11 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 13 | #include "video_core/renderer_vulkan/wrapper.h" | 12 | #include "video_core/vulkan_common/vulkan_device.h" |
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 14 | 14 | ||
| 15 | namespace Vulkan { | 15 | namespace Vulkan { |
| 16 | 16 | ||
| 17 | VKUpdateDescriptorQueue::VKUpdateDescriptorQueue(const VKDevice& device, VKScheduler& scheduler) | 17 | VKUpdateDescriptorQueue::VKUpdateDescriptorQueue(const Device& device_, VKScheduler& scheduler_) |
| 18 | : device{device}, scheduler{scheduler} {} | 18 | : device{device_}, scheduler{scheduler_} {} |
| 19 | 19 | ||
| 20 | VKUpdateDescriptorQueue::~VKUpdateDescriptorQueue() = default; | 20 | VKUpdateDescriptorQueue::~VKUpdateDescriptorQueue() = default; |
| 21 | 21 | ||
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h index 945320c72..e214f7195 100644 --- a/src/video_core/renderer_vulkan/vk_update_descriptor.h +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h | |||
| @@ -8,11 +8,11 @@ | |||
| 8 | #include <boost/container/static_vector.hpp> | 8 | #include <boost/container/static_vector.hpp> |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 12 | 12 | ||
| 13 | namespace Vulkan { | 13 | namespace Vulkan { |
| 14 | 14 | ||
| 15 | class VKDevice; | 15 | class Device; |
| 16 | class VKScheduler; | 16 | class VKScheduler; |
| 17 | 17 | ||
| 18 | struct DescriptorUpdateEntry { | 18 | struct DescriptorUpdateEntry { |
| @@ -31,7 +31,7 @@ struct DescriptorUpdateEntry { | |||
| 31 | 31 | ||
| 32 | class VKUpdateDescriptorQueue final { | 32 | class VKUpdateDescriptorQueue final { |
| 33 | public: | 33 | public: |
| 34 | explicit VKUpdateDescriptorQueue(const VKDevice& device, VKScheduler& scheduler); | 34 | explicit VKUpdateDescriptorQueue(const Device& device_, VKScheduler& scheduler_); |
| 35 | ~VKUpdateDescriptorQueue(); | 35 | ~VKUpdateDescriptorQueue(); |
| 36 | 36 | ||
| 37 | void TickFrame(); | 37 | void TickFrame(); |
| @@ -40,32 +40,36 @@ public: | |||
| 40 | 40 | ||
| 41 | void Send(VkDescriptorUpdateTemplateKHR update_template, VkDescriptorSet set); | 41 | void Send(VkDescriptorUpdateTemplateKHR update_template, VkDescriptorSet set); |
| 42 | 42 | ||
| 43 | void AddSampledImage(VkSampler sampler, VkImageView image_view) { | 43 | void AddSampledImage(VkImageView image_view, VkSampler sampler) { |
| 44 | payload.emplace_back(VkDescriptorImageInfo{sampler, image_view, {}}); | 44 | payload.emplace_back(VkDescriptorImageInfo{ |
| 45 | .sampler = sampler, | ||
| 46 | .imageView = image_view, | ||
| 47 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 48 | }); | ||
| 45 | } | 49 | } |
| 46 | 50 | ||
| 47 | void AddImage(VkImageView image_view) { | 51 | void AddImage(VkImageView image_view) { |
| 48 | payload.emplace_back(VkDescriptorImageInfo{{}, image_view, {}}); | 52 | payload.emplace_back(VkDescriptorImageInfo{ |
| 53 | .sampler = VK_NULL_HANDLE, | ||
| 54 | .imageView = image_view, | ||
| 55 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 56 | }); | ||
| 49 | } | 57 | } |
| 50 | 58 | ||
| 51 | void AddBuffer(VkBuffer buffer, u64 offset, std::size_t size) { | 59 | void AddBuffer(VkBuffer buffer, u64 offset, size_t size) { |
| 52 | payload.emplace_back(VkDescriptorBufferInfo{buffer, offset, size}); | 60 | payload.emplace_back(VkDescriptorBufferInfo{ |
| 61 | .buffer = buffer, | ||
| 62 | .offset = offset, | ||
| 63 | .range = size, | ||
| 64 | }); | ||
| 53 | } | 65 | } |
| 54 | 66 | ||
| 55 | void AddTexelBuffer(VkBufferView texel_buffer) { | 67 | void AddTexelBuffer(VkBufferView texel_buffer) { |
| 56 | payload.emplace_back(texel_buffer); | 68 | payload.emplace_back(texel_buffer); |
| 57 | } | 69 | } |
| 58 | 70 | ||
| 59 | VkImageLayout* LastImageLayout() { | ||
| 60 | return &payload.back().image.imageLayout; | ||
| 61 | } | ||
| 62 | |||
| 63 | const VkImageLayout* LastImageLayout() const { | ||
| 64 | return &payload.back().image.imageLayout; | ||
| 65 | } | ||
| 66 | |||
| 67 | private: | 71 | private: |
| 68 | const VKDevice& device; | 72 | const Device& device; |
| 69 | VKScheduler& scheduler; | 73 | VKScheduler& scheduler; |
| 70 | 74 | ||
| 71 | const DescriptorUpdateEntry* upload_start = nullptr; | 75 | const DescriptorUpdateEntry* upload_start = nullptr; |
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp deleted file mode 100644 index 1fb14e190..000000000 --- a/src/video_core/renderer_vulkan/wrapper.cpp +++ /dev/null | |||
| @@ -1,826 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <exception> | ||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | #include <utility> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | |||
| 14 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 15 | |||
| 16 | namespace Vulkan::vk { | ||
| 17 | |||
| 18 | namespace { | ||
| 19 | |||
| 20 | void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) { | ||
| 21 | std::stable_sort(devices.begin(), devices.end(), [&](auto lhs, auto rhs) { | ||
| 22 | // This will call Vulkan more than needed, but these calls are cheap. | ||
| 23 | const auto lhs_properties = vk::PhysicalDevice(lhs, dld).GetProperties(); | ||
| 24 | const auto rhs_properties = vk::PhysicalDevice(rhs, dld).GetProperties(); | ||
| 25 | |||
| 26 | // Prefer discrete GPUs, Nvidia over AMD, AMD over Intel, Intel over the rest. | ||
| 27 | const bool preferred = | ||
| 28 | (lhs_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && | ||
| 29 | rhs_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) || | ||
| 30 | (lhs_properties.vendorID == 0x10DE && rhs_properties.vendorID != 0x10DE) || | ||
| 31 | (lhs_properties.vendorID == 0x1002 && rhs_properties.vendorID != 0x1002) || | ||
| 32 | (lhs_properties.vendorID == 0x8086 && rhs_properties.vendorID != 0x8086); | ||
| 33 | return !preferred; | ||
| 34 | }); | ||
| 35 | } | ||
| 36 | |||
| 37 | template <typename T> | ||
| 38 | bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name, | ||
| 39 | VkInstance instance = nullptr) noexcept { | ||
| 40 | result = reinterpret_cast<T>(dld.vkGetInstanceProcAddr(instance, proc_name)); | ||
| 41 | return result != nullptr; | ||
| 42 | } | ||
| 43 | |||
| 44 | template <typename T> | ||
| 45 | void Proc(T& result, const DeviceDispatch& dld, const char* proc_name, VkDevice device) noexcept { | ||
| 46 | result = reinterpret_cast<T>(dld.vkGetDeviceProcAddr(device, proc_name)); | ||
| 47 | } | ||
| 48 | |||
| 49 | void Load(VkDevice device, DeviceDispatch& dld) noexcept { | ||
| 50 | #define X(name) Proc(dld.name, dld, #name, device) | ||
| 51 | X(vkAcquireNextImageKHR); | ||
| 52 | X(vkAllocateCommandBuffers); | ||
| 53 | X(vkAllocateDescriptorSets); | ||
| 54 | X(vkAllocateMemory); | ||
| 55 | X(vkBeginCommandBuffer); | ||
| 56 | X(vkBindBufferMemory); | ||
| 57 | X(vkBindImageMemory); | ||
| 58 | X(vkCmdBeginQuery); | ||
| 59 | X(vkCmdBeginRenderPass); | ||
| 60 | X(vkCmdBeginTransformFeedbackEXT); | ||
| 61 | X(vkCmdBindDescriptorSets); | ||
| 62 | X(vkCmdBindIndexBuffer); | ||
| 63 | X(vkCmdBindPipeline); | ||
| 64 | X(vkCmdBindTransformFeedbackBuffersEXT); | ||
| 65 | X(vkCmdBindVertexBuffers); | ||
| 66 | X(vkCmdBlitImage); | ||
| 67 | X(vkCmdClearAttachments); | ||
| 68 | X(vkCmdCopyBuffer); | ||
| 69 | X(vkCmdCopyBufferToImage); | ||
| 70 | X(vkCmdCopyImage); | ||
| 71 | X(vkCmdCopyImageToBuffer); | ||
| 72 | X(vkCmdDispatch); | ||
| 73 | X(vkCmdDraw); | ||
| 74 | X(vkCmdDrawIndexed); | ||
| 75 | X(vkCmdEndQuery); | ||
| 76 | X(vkCmdEndRenderPass); | ||
| 77 | X(vkCmdEndTransformFeedbackEXT); | ||
| 78 | X(vkCmdFillBuffer); | ||
| 79 | X(vkCmdPipelineBarrier); | ||
| 80 | X(vkCmdPushConstants); | ||
| 81 | X(vkCmdSetBlendConstants); | ||
| 82 | X(vkCmdSetDepthBias); | ||
| 83 | X(vkCmdSetDepthBounds); | ||
| 84 | X(vkCmdSetEvent); | ||
| 85 | X(vkCmdSetScissor); | ||
| 86 | X(vkCmdSetStencilCompareMask); | ||
| 87 | X(vkCmdSetStencilReference); | ||
| 88 | X(vkCmdSetStencilWriteMask); | ||
| 89 | X(vkCmdSetViewport); | ||
| 90 | X(vkCmdWaitEvents); | ||
| 91 | X(vkCmdBindVertexBuffers2EXT); | ||
| 92 | X(vkCmdSetCullModeEXT); | ||
| 93 | X(vkCmdSetDepthBoundsTestEnableEXT); | ||
| 94 | X(vkCmdSetDepthCompareOpEXT); | ||
| 95 | X(vkCmdSetDepthTestEnableEXT); | ||
| 96 | X(vkCmdSetDepthWriteEnableEXT); | ||
| 97 | X(vkCmdSetFrontFaceEXT); | ||
| 98 | X(vkCmdSetPrimitiveTopologyEXT); | ||
| 99 | X(vkCmdSetStencilOpEXT); | ||
| 100 | X(vkCmdSetStencilTestEnableEXT); | ||
| 101 | X(vkCreateBuffer); | ||
| 102 | X(vkCreateBufferView); | ||
| 103 | X(vkCreateCommandPool); | ||
| 104 | X(vkCreateComputePipelines); | ||
| 105 | X(vkCreateDescriptorPool); | ||
| 106 | X(vkCreateDescriptorSetLayout); | ||
| 107 | X(vkCreateDescriptorUpdateTemplateKHR); | ||
| 108 | X(vkCreateEvent); | ||
| 109 | X(vkCreateFence); | ||
| 110 | X(vkCreateFramebuffer); | ||
| 111 | X(vkCreateGraphicsPipelines); | ||
| 112 | X(vkCreateImage); | ||
| 113 | X(vkCreateImageView); | ||
| 114 | X(vkCreatePipelineLayout); | ||
| 115 | X(vkCreateQueryPool); | ||
| 116 | X(vkCreateRenderPass); | ||
| 117 | X(vkCreateSampler); | ||
| 118 | X(vkCreateSemaphore); | ||
| 119 | X(vkCreateShaderModule); | ||
| 120 | X(vkCreateSwapchainKHR); | ||
| 121 | X(vkDestroyBuffer); | ||
| 122 | X(vkDestroyBufferView); | ||
| 123 | X(vkDestroyCommandPool); | ||
| 124 | X(vkDestroyDescriptorPool); | ||
| 125 | X(vkDestroyDescriptorSetLayout); | ||
| 126 | X(vkDestroyDescriptorUpdateTemplateKHR); | ||
| 127 | X(vkDestroyEvent); | ||
| 128 | X(vkDestroyFence); | ||
| 129 | X(vkDestroyFramebuffer); | ||
| 130 | X(vkDestroyImage); | ||
| 131 | X(vkDestroyImageView); | ||
| 132 | X(vkDestroyPipeline); | ||
| 133 | X(vkDestroyPipelineLayout); | ||
| 134 | X(vkDestroyQueryPool); | ||
| 135 | X(vkDestroyRenderPass); | ||
| 136 | X(vkDestroySampler); | ||
| 137 | X(vkDestroySemaphore); | ||
| 138 | X(vkDestroyShaderModule); | ||
| 139 | X(vkDestroySwapchainKHR); | ||
| 140 | X(vkDeviceWaitIdle); | ||
| 141 | X(vkEndCommandBuffer); | ||
| 142 | X(vkFreeCommandBuffers); | ||
| 143 | X(vkFreeDescriptorSets); | ||
| 144 | X(vkFreeMemory); | ||
| 145 | X(vkGetBufferMemoryRequirements); | ||
| 146 | X(vkGetDeviceQueue); | ||
| 147 | X(vkGetEventStatus); | ||
| 148 | X(vkGetFenceStatus); | ||
| 149 | X(vkGetImageMemoryRequirements); | ||
| 150 | X(vkGetQueryPoolResults); | ||
| 151 | X(vkGetSemaphoreCounterValueKHR); | ||
| 152 | X(vkMapMemory); | ||
| 153 | X(vkQueueSubmit); | ||
| 154 | X(vkResetFences); | ||
| 155 | X(vkResetQueryPoolEXT); | ||
| 156 | X(vkUnmapMemory); | ||
| 157 | X(vkUpdateDescriptorSetWithTemplateKHR); | ||
| 158 | X(vkUpdateDescriptorSets); | ||
| 159 | X(vkWaitForFences); | ||
| 160 | X(vkWaitSemaphoresKHR); | ||
| 161 | #undef X | ||
| 162 | } | ||
| 163 | |||
| 164 | } // Anonymous namespace | ||
| 165 | |||
| 166 | bool Load(InstanceDispatch& dld) noexcept { | ||
| 167 | #define X(name) Proc(dld.name, dld, #name) | ||
| 168 | return X(vkCreateInstance) && X(vkEnumerateInstanceExtensionProperties) && | ||
| 169 | X(vkEnumerateInstanceLayerProperties); | ||
| 170 | #undef X | ||
| 171 | } | ||
| 172 | |||
| 173 | bool Load(VkInstance instance, InstanceDispatch& dld) noexcept { | ||
| 174 | #define X(name) Proc(dld.name, dld, #name, instance) | ||
| 175 | // These functions may fail to load depending on the enabled extensions. | ||
| 176 | // Don't return a failure on these. | ||
| 177 | X(vkCreateDebugUtilsMessengerEXT); | ||
| 178 | X(vkDestroyDebugUtilsMessengerEXT); | ||
| 179 | X(vkDestroySurfaceKHR); | ||
| 180 | X(vkGetPhysicalDeviceFeatures2KHR); | ||
| 181 | X(vkGetPhysicalDeviceProperties2KHR); | ||
| 182 | X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); | ||
| 183 | X(vkGetPhysicalDeviceSurfaceFormatsKHR); | ||
| 184 | X(vkGetPhysicalDeviceSurfacePresentModesKHR); | ||
| 185 | X(vkGetPhysicalDeviceSurfaceSupportKHR); | ||
| 186 | X(vkGetSwapchainImagesKHR); | ||
| 187 | X(vkQueuePresentKHR); | ||
| 188 | |||
| 189 | return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) && | ||
| 190 | X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) && | ||
| 191 | X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) && | ||
| 192 | X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) && | ||
| 193 | X(vkGetPhysicalDeviceQueueFamilyProperties); | ||
| 194 | #undef X | ||
| 195 | } | ||
| 196 | |||
| 197 | const char* Exception::what() const noexcept { | ||
| 198 | return ToString(result); | ||
| 199 | } | ||
| 200 | |||
| 201 | const char* ToString(VkResult result) noexcept { | ||
| 202 | switch (result) { | ||
| 203 | case VkResult::VK_SUCCESS: | ||
| 204 | return "VK_SUCCESS"; | ||
| 205 | case VkResult::VK_NOT_READY: | ||
| 206 | return "VK_NOT_READY"; | ||
| 207 | case VkResult::VK_TIMEOUT: | ||
| 208 | return "VK_TIMEOUT"; | ||
| 209 | case VkResult::VK_EVENT_SET: | ||
| 210 | return "VK_EVENT_SET"; | ||
| 211 | case VkResult::VK_EVENT_RESET: | ||
| 212 | return "VK_EVENT_RESET"; | ||
| 213 | case VkResult::VK_INCOMPLETE: | ||
| 214 | return "VK_INCOMPLETE"; | ||
| 215 | case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY: | ||
| 216 | return "VK_ERROR_OUT_OF_HOST_MEMORY"; | ||
| 217 | case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY: | ||
| 218 | return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; | ||
| 219 | case VkResult::VK_ERROR_INITIALIZATION_FAILED: | ||
| 220 | return "VK_ERROR_INITIALIZATION_FAILED"; | ||
| 221 | case VkResult::VK_ERROR_DEVICE_LOST: | ||
| 222 | return "VK_ERROR_DEVICE_LOST"; | ||
| 223 | case VkResult::VK_ERROR_MEMORY_MAP_FAILED: | ||
| 224 | return "VK_ERROR_MEMORY_MAP_FAILED"; | ||
| 225 | case VkResult::VK_ERROR_LAYER_NOT_PRESENT: | ||
| 226 | return "VK_ERROR_LAYER_NOT_PRESENT"; | ||
| 227 | case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT: | ||
| 228 | return "VK_ERROR_EXTENSION_NOT_PRESENT"; | ||
| 229 | case VkResult::VK_ERROR_FEATURE_NOT_PRESENT: | ||
| 230 | return "VK_ERROR_FEATURE_NOT_PRESENT"; | ||
| 231 | case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER: | ||
| 232 | return "VK_ERROR_INCOMPATIBLE_DRIVER"; | ||
| 233 | case VkResult::VK_ERROR_TOO_MANY_OBJECTS: | ||
| 234 | return "VK_ERROR_TOO_MANY_OBJECTS"; | ||
| 235 | case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED: | ||
| 236 | return "VK_ERROR_FORMAT_NOT_SUPPORTED"; | ||
| 237 | case VkResult::VK_ERROR_FRAGMENTED_POOL: | ||
| 238 | return "VK_ERROR_FRAGMENTED_POOL"; | ||
| 239 | case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY: | ||
| 240 | return "VK_ERROR_OUT_OF_POOL_MEMORY"; | ||
| 241 | case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE: | ||
| 242 | return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; | ||
| 243 | case VkResult::VK_ERROR_SURFACE_LOST_KHR: | ||
| 244 | return "VK_ERROR_SURFACE_LOST_KHR"; | ||
| 245 | case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: | ||
| 246 | return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; | ||
| 247 | case VkResult::VK_SUBOPTIMAL_KHR: | ||
| 248 | return "VK_SUBOPTIMAL_KHR"; | ||
| 249 | case VkResult::VK_ERROR_OUT_OF_DATE_KHR: | ||
| 250 | return "VK_ERROR_OUT_OF_DATE_KHR"; | ||
| 251 | case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: | ||
| 252 | return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; | ||
| 253 | case VkResult::VK_ERROR_VALIDATION_FAILED_EXT: | ||
| 254 | return "VK_ERROR_VALIDATION_FAILED_EXT"; | ||
| 255 | case VkResult::VK_ERROR_INVALID_SHADER_NV: | ||
| 256 | return "VK_ERROR_INVALID_SHADER_NV"; | ||
| 257 | case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: | ||
| 258 | return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; | ||
| 259 | case VkResult::VK_ERROR_FRAGMENTATION_EXT: | ||
| 260 | return "VK_ERROR_FRAGMENTATION_EXT"; | ||
| 261 | case VkResult::VK_ERROR_NOT_PERMITTED_EXT: | ||
| 262 | return "VK_ERROR_NOT_PERMITTED_EXT"; | ||
| 263 | case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT: | ||
| 264 | return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT"; | ||
| 265 | case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: | ||
| 266 | return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; | ||
| 267 | case VkResult::VK_ERROR_UNKNOWN: | ||
| 268 | return "VK_ERROR_UNKNOWN"; | ||
| 269 | case VkResult::VK_ERROR_INCOMPATIBLE_VERSION_KHR: | ||
| 270 | return "VK_ERROR_INCOMPATIBLE_VERSION_KHR"; | ||
| 271 | case VkResult::VK_THREAD_IDLE_KHR: | ||
| 272 | return "VK_THREAD_IDLE_KHR"; | ||
| 273 | case VkResult::VK_THREAD_DONE_KHR: | ||
| 274 | return "VK_THREAD_DONE_KHR"; | ||
| 275 | case VkResult::VK_OPERATION_DEFERRED_KHR: | ||
| 276 | return "VK_OPERATION_DEFERRED_KHR"; | ||
| 277 | case VkResult::VK_OPERATION_NOT_DEFERRED_KHR: | ||
| 278 | return "VK_OPERATION_NOT_DEFERRED_KHR"; | ||
| 279 | case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT: | ||
| 280 | return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; | ||
| 281 | case VkResult::VK_RESULT_MAX_ENUM: | ||
| 282 | return "VK_RESULT_MAX_ENUM"; | ||
| 283 | } | ||
| 284 | return "Unknown"; | ||
| 285 | } | ||
| 286 | |||
| 287 | void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept { | ||
| 288 | dld.vkDestroyInstance(instance, nullptr); | ||
| 289 | } | ||
| 290 | |||
| 291 | void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept { | ||
| 292 | dld.vkDestroyDevice(device, nullptr); | ||
| 293 | } | ||
| 294 | |||
| 295 | void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexcept { | ||
| 296 | dld.vkDestroyBuffer(device, handle, nullptr); | ||
| 297 | } | ||
| 298 | |||
| 299 | void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept { | ||
| 300 | dld.vkDestroyBufferView(device, handle, nullptr); | ||
| 301 | } | ||
| 302 | |||
| 303 | void Destroy(VkDevice device, VkCommandPool handle, const DeviceDispatch& dld) noexcept { | ||
| 304 | dld.vkDestroyCommandPool(device, handle, nullptr); | ||
| 305 | } | ||
| 306 | |||
| 307 | void Destroy(VkDevice device, VkDescriptorPool handle, const DeviceDispatch& dld) noexcept { | ||
| 308 | dld.vkDestroyDescriptorPool(device, handle, nullptr); | ||
| 309 | } | ||
| 310 | |||
| 311 | void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch& dld) noexcept { | ||
| 312 | dld.vkDestroyDescriptorSetLayout(device, handle, nullptr); | ||
| 313 | } | ||
| 314 | |||
| 315 | void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle, | ||
| 316 | const DeviceDispatch& dld) noexcept { | ||
| 317 | dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr); | ||
| 318 | } | ||
| 319 | |||
| 320 | void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept { | ||
| 321 | dld.vkFreeMemory(device, handle, nullptr); | ||
| 322 | } | ||
| 323 | |||
| 324 | void Destroy(VkDevice device, VkEvent handle, const DeviceDispatch& dld) noexcept { | ||
| 325 | dld.vkDestroyEvent(device, handle, nullptr); | ||
| 326 | } | ||
| 327 | |||
| 328 | void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept { | ||
| 329 | dld.vkDestroyFence(device, handle, nullptr); | ||
| 330 | } | ||
| 331 | |||
| 332 | void Destroy(VkDevice device, VkFramebuffer handle, const DeviceDispatch& dld) noexcept { | ||
| 333 | dld.vkDestroyFramebuffer(device, handle, nullptr); | ||
| 334 | } | ||
| 335 | |||
| 336 | void Destroy(VkDevice device, VkImage handle, const DeviceDispatch& dld) noexcept { | ||
| 337 | dld.vkDestroyImage(device, handle, nullptr); | ||
| 338 | } | ||
| 339 | |||
| 340 | void Destroy(VkDevice device, VkImageView handle, const DeviceDispatch& dld) noexcept { | ||
| 341 | dld.vkDestroyImageView(device, handle, nullptr); | ||
| 342 | } | ||
| 343 | |||
| 344 | void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noexcept { | ||
| 345 | dld.vkDestroyPipeline(device, handle, nullptr); | ||
| 346 | } | ||
| 347 | |||
| 348 | void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept { | ||
| 349 | dld.vkDestroyPipelineLayout(device, handle, nullptr); | ||
| 350 | } | ||
| 351 | |||
| 352 | void Destroy(VkDevice device, VkQueryPool handle, const DeviceDispatch& dld) noexcept { | ||
| 353 | dld.vkDestroyQueryPool(device, handle, nullptr); | ||
| 354 | } | ||
| 355 | |||
| 356 | void Destroy(VkDevice device, VkRenderPass handle, const DeviceDispatch& dld) noexcept { | ||
| 357 | dld.vkDestroyRenderPass(device, handle, nullptr); | ||
| 358 | } | ||
| 359 | |||
| 360 | void Destroy(VkDevice device, VkSampler handle, const DeviceDispatch& dld) noexcept { | ||
| 361 | dld.vkDestroySampler(device, handle, nullptr); | ||
| 362 | } | ||
| 363 | |||
| 364 | void Destroy(VkDevice device, VkSwapchainKHR handle, const DeviceDispatch& dld) noexcept { | ||
| 365 | dld.vkDestroySwapchainKHR(device, handle, nullptr); | ||
| 366 | } | ||
| 367 | |||
| 368 | void Destroy(VkDevice device, VkSemaphore handle, const DeviceDispatch& dld) noexcept { | ||
| 369 | dld.vkDestroySemaphore(device, handle, nullptr); | ||
| 370 | } | ||
| 371 | |||
| 372 | void Destroy(VkDevice device, VkShaderModule handle, const DeviceDispatch& dld) noexcept { | ||
| 373 | dld.vkDestroyShaderModule(device, handle, nullptr); | ||
| 374 | } | ||
| 375 | |||
| 376 | void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle, | ||
| 377 | const InstanceDispatch& dld) noexcept { | ||
| 378 | dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); | ||
| 379 | } | ||
| 380 | |||
| 381 | void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { | ||
| 382 | dld.vkDestroySurfaceKHR(instance, handle, nullptr); | ||
| 383 | } | ||
| 384 | |||
| 385 | VkResult Free(VkDevice device, VkDescriptorPool handle, Span<VkDescriptorSet> sets, | ||
| 386 | const DeviceDispatch& dld) noexcept { | ||
| 387 | return dld.vkFreeDescriptorSets(device, handle, sets.size(), sets.data()); | ||
| 388 | } | ||
| 389 | |||
| 390 | VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffers, | ||
| 391 | const DeviceDispatch& dld) noexcept { | ||
| 392 | dld.vkFreeCommandBuffers(device, handle, buffers.size(), buffers.data()); | ||
| 393 | return VK_SUCCESS; | ||
| 394 | } | ||
| 395 | |||
| 396 | Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions, | ||
| 397 | InstanceDispatch& dld) noexcept { | ||
| 398 | static constexpr VkApplicationInfo application_info{ | ||
| 399 | .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, | ||
| 400 | .pNext = nullptr, | ||
| 401 | .pApplicationName = "yuzu Emulator", | ||
| 402 | .applicationVersion = VK_MAKE_VERSION(0, 1, 0), | ||
| 403 | .pEngineName = "yuzu Emulator", | ||
| 404 | .engineVersion = VK_MAKE_VERSION(0, 1, 0), | ||
| 405 | .apiVersion = VK_API_VERSION_1_1, | ||
| 406 | }; | ||
| 407 | |||
| 408 | const VkInstanceCreateInfo ci{ | ||
| 409 | .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | ||
| 410 | .pNext = nullptr, | ||
| 411 | .flags = 0, | ||
| 412 | .pApplicationInfo = &application_info, | ||
| 413 | .enabledLayerCount = layers.size(), | ||
| 414 | .ppEnabledLayerNames = layers.data(), | ||
| 415 | .enabledExtensionCount = extensions.size(), | ||
| 416 | .ppEnabledExtensionNames = extensions.data(), | ||
| 417 | }; | ||
| 418 | |||
| 419 | VkInstance instance; | ||
| 420 | if (dld.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) { | ||
| 421 | // Failed to create the instance. | ||
| 422 | return {}; | ||
| 423 | } | ||
| 424 | if (!Proc(dld.vkDestroyInstance, dld, "vkDestroyInstance", instance)) { | ||
| 425 | // We successfully created an instance but the destroy function couldn't be loaded. | ||
| 426 | // This is a good moment to panic. | ||
| 427 | return {}; | ||
| 428 | } | ||
| 429 | |||
| 430 | return Instance(instance, dld); | ||
| 431 | } | ||
| 432 | |||
| 433 | std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() { | ||
| 434 | u32 num; | ||
| 435 | if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) { | ||
| 436 | return std::nullopt; | ||
| 437 | } | ||
| 438 | std::vector<VkPhysicalDevice> physical_devices(num); | ||
| 439 | if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) { | ||
| 440 | return std::nullopt; | ||
| 441 | } | ||
| 442 | SortPhysicalDevices(physical_devices, *dld); | ||
| 443 | return std::make_optional(std::move(physical_devices)); | ||
| 444 | } | ||
| 445 | |||
| 446 | DebugCallback Instance::TryCreateDebugCallback( | ||
| 447 | PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept { | ||
| 448 | const VkDebugUtilsMessengerCreateInfoEXT ci{ | ||
| 449 | .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, | ||
| 450 | .pNext = nullptr, | ||
| 451 | .flags = 0, | ||
| 452 | .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | | ||
| 453 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | | ||
| 454 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | | ||
| 455 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, | ||
| 456 | .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | | ||
| 457 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | | ||
| 458 | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, | ||
| 459 | .pfnUserCallback = callback, | ||
| 460 | .pUserData = nullptr, | ||
| 461 | }; | ||
| 462 | |||
| 463 | VkDebugUtilsMessengerEXT messenger; | ||
| 464 | if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) { | ||
| 465 | return {}; | ||
| 466 | } | ||
| 467 | return DebugCallback(messenger, handle, *dld); | ||
| 468 | } | ||
| 469 | |||
| 470 | void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | ||
| 471 | Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); | ||
| 472 | } | ||
| 473 | |||
| 474 | void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | ||
| 475 | Check(dld->vkBindImageMemory(owner, handle, memory, offset)); | ||
| 476 | } | ||
| 477 | |||
| 478 | DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const { | ||
| 479 | const std::size_t num = ai.descriptorSetCount; | ||
| 480 | std::unique_ptr sets = std::make_unique<VkDescriptorSet[]>(num); | ||
| 481 | switch (const VkResult result = dld->vkAllocateDescriptorSets(owner, &ai, sets.get())) { | ||
| 482 | case VK_SUCCESS: | ||
| 483 | return DescriptorSets(std::move(sets), num, owner, handle, *dld); | ||
| 484 | case VK_ERROR_OUT_OF_POOL_MEMORY: | ||
| 485 | return {}; | ||
| 486 | default: | ||
| 487 | throw Exception(result); | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const { | ||
| 492 | const VkCommandBufferAllocateInfo ai{ | ||
| 493 | .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | ||
| 494 | .pNext = nullptr, | ||
| 495 | .commandPool = handle, | ||
| 496 | .level = level, | ||
| 497 | .commandBufferCount = static_cast<u32>(num_buffers), | ||
| 498 | }; | ||
| 499 | |||
| 500 | std::unique_ptr buffers = std::make_unique<VkCommandBuffer[]>(num_buffers); | ||
| 501 | switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) { | ||
| 502 | case VK_SUCCESS: | ||
| 503 | return CommandBuffers(std::move(buffers), num_buffers, owner, handle, *dld); | ||
| 504 | case VK_ERROR_OUT_OF_POOL_MEMORY: | ||
| 505 | return {}; | ||
| 506 | default: | ||
| 507 | throw Exception(result); | ||
| 508 | } | ||
| 509 | } | ||
| 510 | |||
| 511 | std::vector<VkImage> SwapchainKHR::GetImages() const { | ||
| 512 | u32 num; | ||
| 513 | Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr)); | ||
| 514 | std::vector<VkImage> images(num); | ||
| 515 | Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, images.data())); | ||
| 516 | return images; | ||
| 517 | } | ||
| 518 | |||
| 519 | Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, | ||
| 520 | Span<const char*> enabled_extensions, const void* next, | ||
| 521 | DeviceDispatch& dld) noexcept { | ||
| 522 | const VkDeviceCreateInfo ci{ | ||
| 523 | .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, | ||
| 524 | .pNext = next, | ||
| 525 | .flags = 0, | ||
| 526 | .queueCreateInfoCount = queues_ci.size(), | ||
| 527 | .pQueueCreateInfos = queues_ci.data(), | ||
| 528 | .enabledLayerCount = 0, | ||
| 529 | .ppEnabledLayerNames = nullptr, | ||
| 530 | .enabledExtensionCount = enabled_extensions.size(), | ||
| 531 | .ppEnabledExtensionNames = enabled_extensions.data(), | ||
| 532 | .pEnabledFeatures = nullptr, | ||
| 533 | }; | ||
| 534 | |||
| 535 | VkDevice device; | ||
| 536 | if (dld.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) { | ||
| 537 | return {}; | ||
| 538 | } | ||
| 539 | Load(device, dld); | ||
| 540 | return Device(device, dld); | ||
| 541 | } | ||
| 542 | |||
| 543 | Queue Device::GetQueue(u32 family_index) const noexcept { | ||
| 544 | VkQueue queue; | ||
| 545 | dld->vkGetDeviceQueue(handle, family_index, 0, &queue); | ||
| 546 | return Queue(queue, *dld); | ||
| 547 | } | ||
| 548 | |||
| 549 | Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const { | ||
| 550 | VkBuffer object; | ||
| 551 | Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object)); | ||
| 552 | return Buffer(object, handle, *dld); | ||
| 553 | } | ||
| 554 | |||
| 555 | BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { | ||
| 556 | VkBufferView object; | ||
| 557 | Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); | ||
| 558 | return BufferView(object, handle, *dld); | ||
| 559 | } | ||
| 560 | |||
| 561 | Image Device::CreateImage(const VkImageCreateInfo& ci) const { | ||
| 562 | VkImage object; | ||
| 563 | Check(dld->vkCreateImage(handle, &ci, nullptr, &object)); | ||
| 564 | return Image(object, handle, *dld); | ||
| 565 | } | ||
| 566 | |||
| 567 | ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { | ||
| 568 | VkImageView object; | ||
| 569 | Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); | ||
| 570 | return ImageView(object, handle, *dld); | ||
| 571 | } | ||
| 572 | |||
| 573 | Semaphore Device::CreateSemaphore() const { | ||
| 574 | static constexpr VkSemaphoreCreateInfo ci{ | ||
| 575 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, | ||
| 576 | .pNext = nullptr, | ||
| 577 | .flags = 0, | ||
| 578 | }; | ||
| 579 | return CreateSemaphore(ci); | ||
| 580 | } | ||
| 581 | |||
| 582 | Semaphore Device::CreateSemaphore(const VkSemaphoreCreateInfo& ci) const { | ||
| 583 | VkSemaphore object; | ||
| 584 | Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object)); | ||
| 585 | return Semaphore(object, handle, *dld); | ||
| 586 | } | ||
| 587 | |||
| 588 | Fence Device::CreateFence(const VkFenceCreateInfo& ci) const { | ||
| 589 | VkFence object; | ||
| 590 | Check(dld->vkCreateFence(handle, &ci, nullptr, &object)); | ||
| 591 | return Fence(object, handle, *dld); | ||
| 592 | } | ||
| 593 | |||
| 594 | DescriptorPool Device::CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const { | ||
| 595 | VkDescriptorPool object; | ||
| 596 | Check(dld->vkCreateDescriptorPool(handle, &ci, nullptr, &object)); | ||
| 597 | return DescriptorPool(object, handle, *dld); | ||
| 598 | } | ||
| 599 | |||
| 600 | RenderPass Device::CreateRenderPass(const VkRenderPassCreateInfo& ci) const { | ||
| 601 | VkRenderPass object; | ||
| 602 | Check(dld->vkCreateRenderPass(handle, &ci, nullptr, &object)); | ||
| 603 | return RenderPass(object, handle, *dld); | ||
| 604 | } | ||
| 605 | |||
| 606 | DescriptorSetLayout Device::CreateDescriptorSetLayout( | ||
| 607 | const VkDescriptorSetLayoutCreateInfo& ci) const { | ||
| 608 | VkDescriptorSetLayout object; | ||
| 609 | Check(dld->vkCreateDescriptorSetLayout(handle, &ci, nullptr, &object)); | ||
| 610 | return DescriptorSetLayout(object, handle, *dld); | ||
| 611 | } | ||
| 612 | |||
| 613 | PipelineLayout Device::CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const { | ||
| 614 | VkPipelineLayout object; | ||
| 615 | Check(dld->vkCreatePipelineLayout(handle, &ci, nullptr, &object)); | ||
| 616 | return PipelineLayout(object, handle, *dld); | ||
| 617 | } | ||
| 618 | |||
| 619 | Pipeline Device::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const { | ||
| 620 | VkPipeline object; | ||
| 621 | Check(dld->vkCreateGraphicsPipelines(handle, nullptr, 1, &ci, nullptr, &object)); | ||
| 622 | return Pipeline(object, handle, *dld); | ||
| 623 | } | ||
| 624 | |||
| 625 | Pipeline Device::CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const { | ||
| 626 | VkPipeline object; | ||
| 627 | Check(dld->vkCreateComputePipelines(handle, nullptr, 1, &ci, nullptr, &object)); | ||
| 628 | return Pipeline(object, handle, *dld); | ||
| 629 | } | ||
| 630 | |||
| 631 | Sampler Device::CreateSampler(const VkSamplerCreateInfo& ci) const { | ||
| 632 | VkSampler object; | ||
| 633 | Check(dld->vkCreateSampler(handle, &ci, nullptr, &object)); | ||
| 634 | return Sampler(object, handle, *dld); | ||
| 635 | } | ||
| 636 | |||
| 637 | Framebuffer Device::CreateFramebuffer(const VkFramebufferCreateInfo& ci) const { | ||
| 638 | VkFramebuffer object; | ||
| 639 | Check(dld->vkCreateFramebuffer(handle, &ci, nullptr, &object)); | ||
| 640 | return Framebuffer(object, handle, *dld); | ||
| 641 | } | ||
| 642 | |||
| 643 | CommandPool Device::CreateCommandPool(const VkCommandPoolCreateInfo& ci) const { | ||
| 644 | VkCommandPool object; | ||
| 645 | Check(dld->vkCreateCommandPool(handle, &ci, nullptr, &object)); | ||
| 646 | return CommandPool(object, handle, *dld); | ||
| 647 | } | ||
| 648 | |||
| 649 | DescriptorUpdateTemplateKHR Device::CreateDescriptorUpdateTemplateKHR( | ||
| 650 | const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const { | ||
| 651 | VkDescriptorUpdateTemplateKHR object; | ||
| 652 | Check(dld->vkCreateDescriptorUpdateTemplateKHR(handle, &ci, nullptr, &object)); | ||
| 653 | return DescriptorUpdateTemplateKHR(object, handle, *dld); | ||
| 654 | } | ||
| 655 | |||
| 656 | QueryPool Device::CreateQueryPool(const VkQueryPoolCreateInfo& ci) const { | ||
| 657 | VkQueryPool object; | ||
| 658 | Check(dld->vkCreateQueryPool(handle, &ci, nullptr, &object)); | ||
| 659 | return QueryPool(object, handle, *dld); | ||
| 660 | } | ||
| 661 | |||
| 662 | ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) const { | ||
| 663 | VkShaderModule object; | ||
| 664 | Check(dld->vkCreateShaderModule(handle, &ci, nullptr, &object)); | ||
| 665 | return ShaderModule(object, handle, *dld); | ||
| 666 | } | ||
| 667 | |||
| 668 | Event Device::CreateEvent() const { | ||
| 669 | static constexpr VkEventCreateInfo ci{ | ||
| 670 | .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, | ||
| 671 | .pNext = nullptr, | ||
| 672 | .flags = 0, | ||
| 673 | }; | ||
| 674 | |||
| 675 | VkEvent object; | ||
| 676 | Check(dld->vkCreateEvent(handle, &ci, nullptr, &object)); | ||
| 677 | return Event(object, handle, *dld); | ||
| 678 | } | ||
| 679 | |||
| 680 | SwapchainKHR Device::CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const { | ||
| 681 | VkSwapchainKHR object; | ||
| 682 | Check(dld->vkCreateSwapchainKHR(handle, &ci, nullptr, &object)); | ||
| 683 | return SwapchainKHR(object, handle, *dld); | ||
| 684 | } | ||
| 685 | |||
| 686 | DeviceMemory Device::TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept { | ||
| 687 | VkDeviceMemory memory; | ||
| 688 | if (dld->vkAllocateMemory(handle, &ai, nullptr, &memory) != VK_SUCCESS) { | ||
| 689 | return {}; | ||
| 690 | } | ||
| 691 | return DeviceMemory(memory, handle, *dld); | ||
| 692 | } | ||
| 693 | |||
| 694 | DeviceMemory Device::AllocateMemory(const VkMemoryAllocateInfo& ai) const { | ||
| 695 | VkDeviceMemory memory; | ||
| 696 | Check(dld->vkAllocateMemory(handle, &ai, nullptr, &memory)); | ||
| 697 | return DeviceMemory(memory, handle, *dld); | ||
| 698 | } | ||
| 699 | |||
| 700 | VkMemoryRequirements Device::GetBufferMemoryRequirements(VkBuffer buffer) const noexcept { | ||
| 701 | VkMemoryRequirements requirements; | ||
| 702 | dld->vkGetBufferMemoryRequirements(handle, buffer, &requirements); | ||
| 703 | return requirements; | ||
| 704 | } | ||
| 705 | |||
| 706 | VkMemoryRequirements Device::GetImageMemoryRequirements(VkImage image) const noexcept { | ||
| 707 | VkMemoryRequirements requirements; | ||
| 708 | dld->vkGetImageMemoryRequirements(handle, image, &requirements); | ||
| 709 | return requirements; | ||
| 710 | } | ||
| 711 | |||
| 712 | void Device::UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes, | ||
| 713 | Span<VkCopyDescriptorSet> copies) const noexcept { | ||
| 714 | dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data()); | ||
| 715 | } | ||
| 716 | |||
| 717 | VkPhysicalDeviceProperties PhysicalDevice::GetProperties() const noexcept { | ||
| 718 | VkPhysicalDeviceProperties properties; | ||
| 719 | dld->vkGetPhysicalDeviceProperties(physical_device, &properties); | ||
| 720 | return properties; | ||
| 721 | } | ||
| 722 | |||
| 723 | void PhysicalDevice::GetProperties2KHR(VkPhysicalDeviceProperties2KHR& properties) const noexcept { | ||
| 724 | dld->vkGetPhysicalDeviceProperties2KHR(physical_device, &properties); | ||
| 725 | } | ||
| 726 | |||
| 727 | VkPhysicalDeviceFeatures PhysicalDevice::GetFeatures() const noexcept { | ||
| 728 | VkPhysicalDeviceFeatures2KHR features2; | ||
| 729 | features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; | ||
| 730 | features2.pNext = nullptr; | ||
| 731 | dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2); | ||
| 732 | return features2.features; | ||
| 733 | } | ||
| 734 | |||
| 735 | void PhysicalDevice::GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR& features) const noexcept { | ||
| 736 | dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features); | ||
| 737 | } | ||
| 738 | |||
| 739 | VkFormatProperties PhysicalDevice::GetFormatProperties(VkFormat format) const noexcept { | ||
| 740 | VkFormatProperties properties; | ||
| 741 | dld->vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties); | ||
| 742 | return properties; | ||
| 743 | } | ||
| 744 | |||
| 745 | std::vector<VkExtensionProperties> PhysicalDevice::EnumerateDeviceExtensionProperties() const { | ||
| 746 | u32 num; | ||
| 747 | dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, nullptr); | ||
| 748 | std::vector<VkExtensionProperties> properties(num); | ||
| 749 | dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, properties.data()); | ||
| 750 | return properties; | ||
| 751 | } | ||
| 752 | |||
| 753 | std::vector<VkQueueFamilyProperties> PhysicalDevice::GetQueueFamilyProperties() const { | ||
| 754 | u32 num; | ||
| 755 | dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, nullptr); | ||
| 756 | std::vector<VkQueueFamilyProperties> properties(num); | ||
| 757 | dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, properties.data()); | ||
| 758 | return properties; | ||
| 759 | } | ||
| 760 | |||
| 761 | bool PhysicalDevice::GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR surface) const { | ||
| 762 | VkBool32 supported; | ||
| 763 | Check(dld->vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_index, surface, | ||
| 764 | &supported)); | ||
| 765 | return supported == VK_TRUE; | ||
| 766 | } | ||
| 767 | |||
| 768 | VkSurfaceCapabilitiesKHR PhysicalDevice::GetSurfaceCapabilitiesKHR(VkSurfaceKHR surface) const { | ||
| 769 | VkSurfaceCapabilitiesKHR capabilities; | ||
| 770 | Check(dld->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &capabilities)); | ||
| 771 | return capabilities; | ||
| 772 | } | ||
| 773 | |||
| 774 | std::vector<VkSurfaceFormatKHR> PhysicalDevice::GetSurfaceFormatsKHR(VkSurfaceKHR surface) const { | ||
| 775 | u32 num; | ||
| 776 | Check(dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, nullptr)); | ||
| 777 | std::vector<VkSurfaceFormatKHR> formats(num); | ||
| 778 | Check( | ||
| 779 | dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, formats.data())); | ||
| 780 | return formats; | ||
| 781 | } | ||
| 782 | |||
| 783 | std::vector<VkPresentModeKHR> PhysicalDevice::GetSurfacePresentModesKHR( | ||
| 784 | VkSurfaceKHR surface) const { | ||
| 785 | u32 num; | ||
| 786 | Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, nullptr)); | ||
| 787 | std::vector<VkPresentModeKHR> modes(num); | ||
| 788 | Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, | ||
| 789 | modes.data())); | ||
| 790 | return modes; | ||
| 791 | } | ||
| 792 | |||
| 793 | VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noexcept { | ||
| 794 | VkPhysicalDeviceMemoryProperties properties; | ||
| 795 | dld->vkGetPhysicalDeviceMemoryProperties(physical_device, &properties); | ||
| 796 | return properties; | ||
| 797 | } | ||
| 798 | |||
| 799 | std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( | ||
| 800 | const InstanceDispatch& dld) { | ||
| 801 | u32 num; | ||
| 802 | if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, nullptr) != VK_SUCCESS) { | ||
| 803 | return std::nullopt; | ||
| 804 | } | ||
| 805 | std::vector<VkExtensionProperties> properties(num); | ||
| 806 | if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, properties.data()) != | ||
| 807 | VK_SUCCESS) { | ||
| 808 | return std::nullopt; | ||
| 809 | } | ||
| 810 | return std::move(properties); | ||
| 811 | } | ||
| 812 | |||
| 813 | std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties( | ||
| 814 | const InstanceDispatch& dld) { | ||
| 815 | u32 num; | ||
| 816 | if (dld.vkEnumerateInstanceLayerProperties(&num, nullptr) != VK_SUCCESS) { | ||
| 817 | return std::nullopt; | ||
| 818 | } | ||
| 819 | std::vector<VkLayerProperties> properties(num); | ||
| 820 | if (dld.vkEnumerateInstanceLayerProperties(&num, properties.data()) != VK_SUCCESS) { | ||
| 821 | return std::nullopt; | ||
| 822 | } | ||
| 823 | return properties; | ||
| 824 | } | ||
| 825 | |||
| 826 | } // namespace Vulkan::vk | ||
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h deleted file mode 100644 index 234e01693..000000000 --- a/src/video_core/renderer_vulkan/wrapper.h +++ /dev/null | |||
| @@ -1,1099 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <exception> | ||
| 8 | #include <iterator> | ||
| 9 | #include <limits> | ||
| 10 | #include <memory> | ||
| 11 | #include <optional> | ||
| 12 | #include <type_traits> | ||
| 13 | #include <utility> | ||
| 14 | #include <vector> | ||
| 15 | |||
| 16 | #define VK_NO_PROTOTYPES | ||
| 17 | #include <vulkan/vulkan.h> | ||
| 18 | |||
| 19 | #include "common/common_types.h" | ||
| 20 | |||
| 21 | namespace Vulkan::vk { | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Span for Vulkan arrays. | ||
| 25 | * Based on std::span but optimized for array access instead of iterators. | ||
| 26 | * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions. | ||
| 27 | */ | ||
| 28 | template <typename T> | ||
| 29 | class Span { | ||
| 30 | public: | ||
| 31 | using value_type = T; | ||
| 32 | using size_type = u32; | ||
| 33 | using difference_type = std::ptrdiff_t; | ||
| 34 | using reference = const T&; | ||
| 35 | using const_reference = const T&; | ||
| 36 | using pointer = const T*; | ||
| 37 | using const_pointer = const T*; | ||
| 38 | using iterator = const T*; | ||
| 39 | using const_iterator = const T*; | ||
| 40 | |||
| 41 | /// Construct an empty span. | ||
| 42 | constexpr Span() noexcept = default; | ||
| 43 | |||
| 44 | /// Construct a span from a single element. | ||
| 45 | constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {} | ||
| 46 | |||
| 47 | /// Construct a span from a range. | ||
| 48 | template <typename Range> | ||
| 49 | // requires std::data(const Range&) | ||
| 50 | // requires std::size(const Range&) | ||
| 51 | constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {} | ||
| 52 | |||
| 53 | /// Construct a span from a pointer and a size. | ||
| 54 | /// This is inteded for subranges. | ||
| 55 | constexpr Span(const T* ptr, std::size_t num) noexcept : ptr{ptr}, num{num} {} | ||
| 56 | |||
| 57 | /// Returns the data pointer by the span. | ||
| 58 | constexpr const T* data() const noexcept { | ||
| 59 | return ptr; | ||
| 60 | } | ||
| 61 | |||
| 62 | /// Returns the number of elements in the span. | ||
| 63 | /// @note Returns a 32 bits integer because most Vulkan functions expect this type. | ||
| 64 | constexpr u32 size() const noexcept { | ||
| 65 | return static_cast<u32>(num); | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Returns true when the span is empty. | ||
| 69 | constexpr bool empty() const noexcept { | ||
| 70 | return num == 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | /// Returns a reference to the element in the passed index. | ||
| 74 | /// @pre: index < size() | ||
| 75 | constexpr const T& operator[](std::size_t index) const noexcept { | ||
| 76 | return ptr[index]; | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Returns an iterator to the beginning of the span. | ||
| 80 | constexpr const T* begin() const noexcept { | ||
| 81 | return ptr; | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Returns an iterator to the end of the span. | ||
| 85 | constexpr const T* end() const noexcept { | ||
| 86 | return ptr + num; | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Returns an iterator to the beginning of the span. | ||
| 90 | constexpr const T* cbegin() const noexcept { | ||
| 91 | return ptr; | ||
| 92 | } | ||
| 93 | |||
| 94 | /// Returns an iterator to the end of the span. | ||
| 95 | constexpr const T* cend() const noexcept { | ||
| 96 | return ptr + num; | ||
| 97 | } | ||
| 98 | |||
| 99 | private: | ||
| 100 | const T* ptr = nullptr; | ||
| 101 | std::size_t num = 0; | ||
| 102 | }; | ||
| 103 | |||
| 104 | /// Vulkan exception generated from a VkResult. | ||
| 105 | class Exception final : public std::exception { | ||
| 106 | public: | ||
| 107 | /// Construct the exception with a result. | ||
| 108 | /// @pre result != VK_SUCCESS | ||
| 109 | explicit Exception(VkResult result_) : result{result_} {} | ||
| 110 | virtual ~Exception() = default; | ||
| 111 | |||
| 112 | const char* what() const noexcept override; | ||
| 113 | |||
| 114 | private: | ||
| 115 | VkResult result; | ||
| 116 | }; | ||
| 117 | |||
| 118 | /// Converts a VkResult enum into a rodata string | ||
| 119 | const char* ToString(VkResult) noexcept; | ||
| 120 | |||
| 121 | /// Throws a Vulkan exception if result is not success. | ||
| 122 | inline void Check(VkResult result) { | ||
| 123 | if (result != VK_SUCCESS) { | ||
| 124 | throw Exception(result); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Throws a Vulkan exception if result is an error. | ||
| 129 | /// @return result | ||
| 130 | inline VkResult Filter(VkResult result) { | ||
| 131 | if (result < 0) { | ||
| 132 | throw Exception(result); | ||
| 133 | } | ||
| 134 | return result; | ||
| 135 | } | ||
| 136 | |||
| 137 | /// Table holding Vulkan instance function pointers. | ||
| 138 | struct InstanceDispatch { | ||
| 139 | PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; | ||
| 140 | |||
| 141 | PFN_vkCreateInstance vkCreateInstance; | ||
| 142 | PFN_vkDestroyInstance vkDestroyInstance; | ||
| 143 | PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; | ||
| 144 | PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; | ||
| 145 | |||
| 146 | PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; | ||
| 147 | PFN_vkCreateDevice vkCreateDevice; | ||
| 148 | PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; | ||
| 149 | PFN_vkDestroyDevice vkDestroyDevice; | ||
| 150 | PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; | ||
| 151 | PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; | ||
| 152 | PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; | ||
| 153 | PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; | ||
| 154 | PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; | ||
| 155 | PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; | ||
| 156 | PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; | ||
| 157 | PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; | ||
| 158 | PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; | ||
| 159 | PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; | ||
| 160 | PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; | ||
| 161 | PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; | ||
| 162 | PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; | ||
| 163 | PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; | ||
| 164 | PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; | ||
| 165 | PFN_vkQueuePresentKHR vkQueuePresentKHR; | ||
| 166 | }; | ||
| 167 | |||
| 168 | /// Table holding Vulkan device function pointers. | ||
| 169 | struct DeviceDispatch : public InstanceDispatch { | ||
| 170 | PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; | ||
| 171 | PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; | ||
| 172 | PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; | ||
| 173 | PFN_vkAllocateMemory vkAllocateMemory; | ||
| 174 | PFN_vkBeginCommandBuffer vkBeginCommandBuffer; | ||
| 175 | PFN_vkBindBufferMemory vkBindBufferMemory; | ||
| 176 | PFN_vkBindImageMemory vkBindImageMemory; | ||
| 177 | PFN_vkCmdBeginQuery vkCmdBeginQuery; | ||
| 178 | PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; | ||
| 179 | PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; | ||
| 180 | PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; | ||
| 181 | PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; | ||
| 182 | PFN_vkCmdBindPipeline vkCmdBindPipeline; | ||
| 183 | PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; | ||
| 184 | PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; | ||
| 185 | PFN_vkCmdBlitImage vkCmdBlitImage; | ||
| 186 | PFN_vkCmdClearAttachments vkCmdClearAttachments; | ||
| 187 | PFN_vkCmdCopyBuffer vkCmdCopyBuffer; | ||
| 188 | PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; | ||
| 189 | PFN_vkCmdCopyImage vkCmdCopyImage; | ||
| 190 | PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; | ||
| 191 | PFN_vkCmdDispatch vkCmdDispatch; | ||
| 192 | PFN_vkCmdDraw vkCmdDraw; | ||
| 193 | PFN_vkCmdDrawIndexed vkCmdDrawIndexed; | ||
| 194 | PFN_vkCmdEndQuery vkCmdEndQuery; | ||
| 195 | PFN_vkCmdEndRenderPass vkCmdEndRenderPass; | ||
| 196 | PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; | ||
| 197 | PFN_vkCmdFillBuffer vkCmdFillBuffer; | ||
| 198 | PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; | ||
| 199 | PFN_vkCmdPushConstants vkCmdPushConstants; | ||
| 200 | PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; | ||
| 201 | PFN_vkCmdSetDepthBias vkCmdSetDepthBias; | ||
| 202 | PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; | ||
| 203 | PFN_vkCmdSetEvent vkCmdSetEvent; | ||
| 204 | PFN_vkCmdSetScissor vkCmdSetScissor; | ||
| 205 | PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; | ||
| 206 | PFN_vkCmdSetStencilReference vkCmdSetStencilReference; | ||
| 207 | PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; | ||
| 208 | PFN_vkCmdSetViewport vkCmdSetViewport; | ||
| 209 | PFN_vkCmdWaitEvents vkCmdWaitEvents; | ||
| 210 | PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; | ||
| 211 | PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; | ||
| 212 | PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; | ||
| 213 | PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; | ||
| 214 | PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; | ||
| 215 | PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; | ||
| 216 | PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; | ||
| 217 | PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; | ||
| 218 | PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; | ||
| 219 | PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; | ||
| 220 | PFN_vkCreateBuffer vkCreateBuffer; | ||
| 221 | PFN_vkCreateBufferView vkCreateBufferView; | ||
| 222 | PFN_vkCreateCommandPool vkCreateCommandPool; | ||
| 223 | PFN_vkCreateComputePipelines vkCreateComputePipelines; | ||
| 224 | PFN_vkCreateDescriptorPool vkCreateDescriptorPool; | ||
| 225 | PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; | ||
| 226 | PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; | ||
| 227 | PFN_vkCreateEvent vkCreateEvent; | ||
| 228 | PFN_vkCreateFence vkCreateFence; | ||
| 229 | PFN_vkCreateFramebuffer vkCreateFramebuffer; | ||
| 230 | PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; | ||
| 231 | PFN_vkCreateImage vkCreateImage; | ||
| 232 | PFN_vkCreateImageView vkCreateImageView; | ||
| 233 | PFN_vkCreatePipelineLayout vkCreatePipelineLayout; | ||
| 234 | PFN_vkCreateQueryPool vkCreateQueryPool; | ||
| 235 | PFN_vkCreateRenderPass vkCreateRenderPass; | ||
| 236 | PFN_vkCreateSampler vkCreateSampler; | ||
| 237 | PFN_vkCreateSemaphore vkCreateSemaphore; | ||
| 238 | PFN_vkCreateShaderModule vkCreateShaderModule; | ||
| 239 | PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; | ||
| 240 | PFN_vkDestroyBuffer vkDestroyBuffer; | ||
| 241 | PFN_vkDestroyBufferView vkDestroyBufferView; | ||
| 242 | PFN_vkDestroyCommandPool vkDestroyCommandPool; | ||
| 243 | PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; | ||
| 244 | PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; | ||
| 245 | PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; | ||
| 246 | PFN_vkDestroyEvent vkDestroyEvent; | ||
| 247 | PFN_vkDestroyFence vkDestroyFence; | ||
| 248 | PFN_vkDestroyFramebuffer vkDestroyFramebuffer; | ||
| 249 | PFN_vkDestroyImage vkDestroyImage; | ||
| 250 | PFN_vkDestroyImageView vkDestroyImageView; | ||
| 251 | PFN_vkDestroyPipeline vkDestroyPipeline; | ||
| 252 | PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; | ||
| 253 | PFN_vkDestroyQueryPool vkDestroyQueryPool; | ||
| 254 | PFN_vkDestroyRenderPass vkDestroyRenderPass; | ||
| 255 | PFN_vkDestroySampler vkDestroySampler; | ||
| 256 | PFN_vkDestroySemaphore vkDestroySemaphore; | ||
| 257 | PFN_vkDestroyShaderModule vkDestroyShaderModule; | ||
| 258 | PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; | ||
| 259 | PFN_vkDeviceWaitIdle vkDeviceWaitIdle; | ||
| 260 | PFN_vkEndCommandBuffer vkEndCommandBuffer; | ||
| 261 | PFN_vkFreeCommandBuffers vkFreeCommandBuffers; | ||
| 262 | PFN_vkFreeDescriptorSets vkFreeDescriptorSets; | ||
| 263 | PFN_vkFreeMemory vkFreeMemory; | ||
| 264 | PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; | ||
| 265 | PFN_vkGetDeviceQueue vkGetDeviceQueue; | ||
| 266 | PFN_vkGetEventStatus vkGetEventStatus; | ||
| 267 | PFN_vkGetFenceStatus vkGetFenceStatus; | ||
| 268 | PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; | ||
| 269 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults; | ||
| 270 | PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; | ||
| 271 | PFN_vkMapMemory vkMapMemory; | ||
| 272 | PFN_vkQueueSubmit vkQueueSubmit; | ||
| 273 | PFN_vkResetFences vkResetFences; | ||
| 274 | PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; | ||
| 275 | PFN_vkUnmapMemory vkUnmapMemory; | ||
| 276 | PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; | ||
| 277 | PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; | ||
| 278 | PFN_vkWaitForFences vkWaitForFences; | ||
| 279 | PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; | ||
| 280 | }; | ||
| 281 | |||
| 282 | /// Loads instance agnostic function pointers. | ||
| 283 | /// @return True on success, false on error. | ||
| 284 | bool Load(InstanceDispatch&) noexcept; | ||
| 285 | |||
| 286 | /// Loads instance function pointers. | ||
| 287 | /// @return True on success, false on error. | ||
| 288 | bool Load(VkInstance, InstanceDispatch&) noexcept; | ||
| 289 | |||
| 290 | void Destroy(VkInstance, const InstanceDispatch&) noexcept; | ||
| 291 | void Destroy(VkDevice, const InstanceDispatch&) noexcept; | ||
| 292 | |||
| 293 | void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept; | ||
| 294 | void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept; | ||
| 295 | void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept; | ||
| 296 | void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept; | ||
| 297 | void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept; | ||
| 298 | void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept; | ||
| 299 | void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept; | ||
| 300 | void Destroy(VkDevice, VkEvent, const DeviceDispatch&) noexcept; | ||
| 301 | void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept; | ||
| 302 | void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept; | ||
| 303 | void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept; | ||
| 304 | void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept; | ||
| 305 | void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept; | ||
| 306 | void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept; | ||
| 307 | void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept; | ||
| 308 | void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept; | ||
| 309 | void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept; | ||
| 310 | void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept; | ||
| 311 | void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; | ||
| 312 | void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; | ||
| 313 | void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; | ||
| 314 | void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; | ||
| 315 | |||
| 316 | VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept; | ||
| 317 | VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept; | ||
| 318 | |||
| 319 | template <typename Type, typename OwnerType, typename Dispatch> | ||
| 320 | class Handle; | ||
| 321 | |||
| 322 | /// Handle with an owning type. | ||
| 323 | /// Analogue to std::unique_ptr. | ||
| 324 | template <typename Type, typename OwnerType, typename Dispatch> | ||
| 325 | class Handle { | ||
| 326 | public: | ||
| 327 | /// Construct a handle and hold it's ownership. | ||
| 328 | explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept | ||
| 329 | : handle{handle_}, owner{owner_}, dld{&dld_} {} | ||
| 330 | |||
| 331 | /// Construct an empty handle. | ||
| 332 | Handle() = default; | ||
| 333 | |||
| 334 | /// Copying Vulkan objects is not supported and will never be. | ||
| 335 | Handle(const Handle&) = delete; | ||
| 336 | Handle& operator=(const Handle&) = delete; | ||
| 337 | |||
| 338 | /// Construct a handle transfering the ownership from another handle. | ||
| 339 | Handle(Handle&& rhs) noexcept | ||
| 340 | : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {} | ||
| 341 | |||
| 342 | /// Assign the current handle transfering the ownership from another handle. | ||
| 343 | /// Destroys any previously held object. | ||
| 344 | Handle& operator=(Handle&& rhs) noexcept { | ||
| 345 | Release(); | ||
| 346 | handle = std::exchange(rhs.handle, nullptr); | ||
| 347 | owner = rhs.owner; | ||
| 348 | dld = rhs.dld; | ||
| 349 | return *this; | ||
| 350 | } | ||
| 351 | |||
| 352 | /// Destroys the current handle if it existed. | ||
| 353 | ~Handle() noexcept { | ||
| 354 | Release(); | ||
| 355 | } | ||
| 356 | |||
| 357 | /// Destroys any held object. | ||
| 358 | void reset() noexcept { | ||
| 359 | Release(); | ||
| 360 | handle = nullptr; | ||
| 361 | } | ||
| 362 | |||
| 363 | /// Returns the address of the held object. | ||
| 364 | /// Intended for Vulkan structures that expect a pointer to an array. | ||
| 365 | const Type* address() const noexcept { | ||
| 366 | return std::addressof(handle); | ||
| 367 | } | ||
| 368 | |||
| 369 | /// Returns the held Vulkan handle. | ||
| 370 | Type operator*() const noexcept { | ||
| 371 | return handle; | ||
| 372 | } | ||
| 373 | |||
| 374 | /// Returns true when there's a held object. | ||
| 375 | explicit operator bool() const noexcept { | ||
| 376 | return handle != nullptr; | ||
| 377 | } | ||
| 378 | |||
| 379 | protected: | ||
| 380 | Type handle = nullptr; | ||
| 381 | OwnerType owner = nullptr; | ||
| 382 | const Dispatch* dld = nullptr; | ||
| 383 | |||
| 384 | private: | ||
| 385 | /// Destroys the held object if it exists. | ||
| 386 | void Release() noexcept { | ||
| 387 | if (handle) { | ||
| 388 | Destroy(owner, handle, *dld); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | }; | ||
| 392 | |||
| 393 | /// Dummy type used to specify a handle has no owner. | ||
| 394 | struct NoOwner {}; | ||
| 395 | |||
| 396 | /// Handle without an owning type. | ||
| 397 | /// Analogue to std::unique_ptr | ||
| 398 | template <typename Type, typename Dispatch> | ||
| 399 | class Handle<Type, NoOwner, Dispatch> { | ||
| 400 | public: | ||
| 401 | /// Construct a handle and hold it's ownership. | ||
| 402 | explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {} | ||
| 403 | |||
| 404 | /// Construct an empty handle. | ||
| 405 | Handle() noexcept = default; | ||
| 406 | |||
| 407 | /// Copying Vulkan objects is not supported and will never be. | ||
| 408 | Handle(const Handle&) = delete; | ||
| 409 | Handle& operator=(const Handle&) = delete; | ||
| 410 | |||
| 411 | /// Construct a handle transfering ownership from another handle. | ||
| 412 | Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {} | ||
| 413 | |||
| 414 | /// Assign the current handle transfering the ownership from another handle. | ||
| 415 | /// Destroys any previously held object. | ||
| 416 | Handle& operator=(Handle&& rhs) noexcept { | ||
| 417 | Release(); | ||
| 418 | handle = std::exchange(rhs.handle, nullptr); | ||
| 419 | dld = rhs.dld; | ||
| 420 | return *this; | ||
| 421 | } | ||
| 422 | |||
| 423 | /// Destroys the current handle if it existed. | ||
| 424 | ~Handle() noexcept { | ||
| 425 | Release(); | ||
| 426 | } | ||
| 427 | |||
| 428 | /// Destroys any held object. | ||
| 429 | void reset() noexcept { | ||
| 430 | Release(); | ||
| 431 | handle = nullptr; | ||
| 432 | } | ||
| 433 | |||
| 434 | /// Returns the address of the held object. | ||
| 435 | /// Intended for Vulkan structures that expect a pointer to an array. | ||
| 436 | const Type* address() const noexcept { | ||
| 437 | return std::addressof(handle); | ||
| 438 | } | ||
| 439 | |||
| 440 | /// Returns the held Vulkan handle. | ||
| 441 | Type operator*() const noexcept { | ||
| 442 | return handle; | ||
| 443 | } | ||
| 444 | |||
| 445 | /// Returns true when there's a held object. | ||
| 446 | operator bool() const noexcept { | ||
| 447 | return handle != nullptr; | ||
| 448 | } | ||
| 449 | |||
| 450 | protected: | ||
| 451 | Type handle = nullptr; | ||
| 452 | const Dispatch* dld = nullptr; | ||
| 453 | |||
| 454 | private: | ||
| 455 | /// Destroys the held object if it exists. | ||
| 456 | void Release() noexcept { | ||
| 457 | if (handle) { | ||
| 458 | Destroy(handle, *dld); | ||
| 459 | } | ||
| 460 | } | ||
| 461 | }; | ||
| 462 | |||
| 463 | /// Array of a pool allocation. | ||
| 464 | /// Analogue to std::vector | ||
| 465 | template <typename AllocationType, typename PoolType> | ||
| 466 | class PoolAllocations { | ||
| 467 | public: | ||
| 468 | /// Construct an empty allocation. | ||
| 469 | PoolAllocations() = default; | ||
| 470 | |||
| 471 | /// Construct an allocation. Errors are reported through IsOutOfPoolMemory(). | ||
| 472 | explicit PoolAllocations(std::unique_ptr<AllocationType[]> allocations, std::size_t num, | ||
| 473 | VkDevice device, PoolType pool, const DeviceDispatch& dld) noexcept | ||
| 474 | : allocations{std::move(allocations)}, num{num}, device{device}, pool{pool}, dld{&dld} {} | ||
| 475 | |||
| 476 | /// Copying Vulkan allocations is not supported and will never be. | ||
| 477 | PoolAllocations(const PoolAllocations&) = delete; | ||
| 478 | PoolAllocations& operator=(const PoolAllocations&) = delete; | ||
| 479 | |||
| 480 | /// Construct an allocation transfering ownership from another allocation. | ||
| 481 | PoolAllocations(PoolAllocations&& rhs) noexcept | ||
| 482 | : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool}, | ||
| 483 | dld{rhs.dld} {} | ||
| 484 | |||
| 485 | /// Assign an allocation transfering ownership from another allocation. | ||
| 486 | /// Releases any previously held allocation. | ||
| 487 | PoolAllocations& operator=(PoolAllocations&& rhs) noexcept { | ||
| 488 | Release(); | ||
| 489 | allocations = std::move(rhs.allocations); | ||
| 490 | num = rhs.num; | ||
| 491 | device = rhs.device; | ||
| 492 | pool = rhs.pool; | ||
| 493 | dld = rhs.dld; | ||
| 494 | return *this; | ||
| 495 | } | ||
| 496 | |||
| 497 | /// Destroys any held allocation. | ||
| 498 | ~PoolAllocations() { | ||
| 499 | Release(); | ||
| 500 | } | ||
| 501 | |||
| 502 | /// Returns the number of allocations. | ||
| 503 | std::size_t size() const noexcept { | ||
| 504 | return num; | ||
| 505 | } | ||
| 506 | |||
| 507 | /// Returns a pointer to the array of allocations. | ||
| 508 | AllocationType const* data() const noexcept { | ||
| 509 | return allocations.get(); | ||
| 510 | } | ||
| 511 | |||
| 512 | /// Returns the allocation in the specified index. | ||
| 513 | /// @pre index < size() | ||
| 514 | AllocationType operator[](std::size_t index) const noexcept { | ||
| 515 | return allocations[index]; | ||
| 516 | } | ||
| 517 | |||
| 518 | /// True when a pool fails to construct. | ||
| 519 | bool IsOutOfPoolMemory() const noexcept { | ||
| 520 | return !device; | ||
| 521 | } | ||
| 522 | |||
| 523 | private: | ||
| 524 | /// Destroys the held allocations if they exist. | ||
| 525 | void Release() noexcept { | ||
| 526 | if (!allocations) { | ||
| 527 | return; | ||
| 528 | } | ||
| 529 | const Span<AllocationType> span(allocations.get(), num); | ||
| 530 | const VkResult result = Free(device, pool, span, *dld); | ||
| 531 | // There's no way to report errors from a destructor. | ||
| 532 | if (result != VK_SUCCESS) { | ||
| 533 | std::terminate(); | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 537 | std::unique_ptr<AllocationType[]> allocations; | ||
| 538 | std::size_t num = 0; | ||
| 539 | VkDevice device = nullptr; | ||
| 540 | PoolType pool = nullptr; | ||
| 541 | const DeviceDispatch* dld = nullptr; | ||
| 542 | }; | ||
| 543 | |||
| 544 | using BufferView = Handle<VkBufferView, VkDevice, DeviceDispatch>; | ||
| 545 | using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; | ||
| 546 | using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; | ||
| 547 | using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>; | ||
| 548 | using Framebuffer = Handle<VkFramebuffer, VkDevice, DeviceDispatch>; | ||
| 549 | using ImageView = Handle<VkImageView, VkDevice, DeviceDispatch>; | ||
| 550 | using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; | ||
| 551 | using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>; | ||
| 552 | using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; | ||
| 553 | using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>; | ||
| 554 | using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>; | ||
| 555 | using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>; | ||
| 556 | using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>; | ||
| 557 | |||
| 558 | using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>; | ||
| 559 | using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>; | ||
| 560 | |||
| 561 | /// Vulkan instance owning handle. | ||
| 562 | class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> { | ||
| 563 | using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle; | ||
| 564 | |||
| 565 | public: | ||
| 566 | /// Creates a Vulkan instance. Use "operator bool" for error handling. | ||
| 567 | static Instance Create(Span<const char*> layers, Span<const char*> extensions, | ||
| 568 | InstanceDispatch& dld) noexcept; | ||
| 569 | |||
| 570 | /// Enumerates physical devices. | ||
| 571 | /// @return Physical devices and an empty handle on failure. | ||
| 572 | std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices(); | ||
| 573 | |||
| 574 | /// Tries to create a debug callback messenger. Returns an empty handle on failure. | ||
| 575 | DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept; | ||
| 576 | }; | ||
| 577 | |||
| 578 | class Queue { | ||
| 579 | public: | ||
| 580 | /// Construct an empty queue handle. | ||
| 581 | constexpr Queue() noexcept = default; | ||
| 582 | |||
| 583 | /// Construct a queue handle. | ||
| 584 | constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {} | ||
| 585 | |||
| 586 | VkResult Submit(Span<VkSubmitInfo> submit_infos, | ||
| 587 | VkFence fence = VK_NULL_HANDLE) const noexcept { | ||
| 588 | return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence); | ||
| 589 | } | ||
| 590 | |||
| 591 | VkResult Present(const VkPresentInfoKHR& present_info) const noexcept { | ||
| 592 | return dld->vkQueuePresentKHR(queue, &present_info); | ||
| 593 | } | ||
| 594 | |||
| 595 | private: | ||
| 596 | VkQueue queue = nullptr; | ||
| 597 | const DeviceDispatch* dld = nullptr; | ||
| 598 | }; | ||
| 599 | |||
| 600 | class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> { | ||
| 601 | using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle; | ||
| 602 | |||
| 603 | public: | ||
| 604 | /// Attaches a memory allocation. | ||
| 605 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | ||
| 606 | }; | ||
| 607 | |||
| 608 | class Image : public Handle<VkImage, VkDevice, DeviceDispatch> { | ||
| 609 | using Handle<VkImage, VkDevice, DeviceDispatch>::Handle; | ||
| 610 | |||
| 611 | public: | ||
| 612 | /// Attaches a memory allocation. | ||
| 613 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | ||
| 614 | }; | ||
| 615 | |||
| 616 | class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> { | ||
| 617 | using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle; | ||
| 618 | |||
| 619 | public: | ||
| 620 | u8* Map(VkDeviceSize offset, VkDeviceSize size) const { | ||
| 621 | void* data; | ||
| 622 | Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data)); | ||
| 623 | return static_cast<u8*>(data); | ||
| 624 | } | ||
| 625 | |||
| 626 | void Unmap() const noexcept { | ||
| 627 | dld->vkUnmapMemory(owner, handle); | ||
| 628 | } | ||
| 629 | }; | ||
| 630 | |||
| 631 | class Fence : public Handle<VkFence, VkDevice, DeviceDispatch> { | ||
| 632 | using Handle<VkFence, VkDevice, DeviceDispatch>::Handle; | ||
| 633 | |||
| 634 | public: | ||
| 635 | VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept { | ||
| 636 | return dld->vkWaitForFences(owner, 1, &handle, true, timeout); | ||
| 637 | } | ||
| 638 | |||
| 639 | VkResult GetStatus() const noexcept { | ||
| 640 | return dld->vkGetFenceStatus(owner, handle); | ||
| 641 | } | ||
| 642 | |||
| 643 | void Reset() const { | ||
| 644 | Check(dld->vkResetFences(owner, 1, &handle)); | ||
| 645 | } | ||
| 646 | }; | ||
| 647 | |||
| 648 | class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> { | ||
| 649 | using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle; | ||
| 650 | |||
| 651 | public: | ||
| 652 | DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const; | ||
| 653 | }; | ||
| 654 | |||
| 655 | class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> { | ||
| 656 | using Handle<VkCommandPool, VkDevice, DeviceDispatch>::Handle; | ||
| 657 | |||
| 658 | public: | ||
| 659 | CommandBuffers Allocate(std::size_t num_buffers, | ||
| 660 | VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const; | ||
| 661 | }; | ||
| 662 | |||
| 663 | class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> { | ||
| 664 | using Handle<VkSwapchainKHR, VkDevice, DeviceDispatch>::Handle; | ||
| 665 | |||
| 666 | public: | ||
| 667 | std::vector<VkImage> GetImages() const; | ||
| 668 | }; | ||
| 669 | |||
| 670 | class Event : public Handle<VkEvent, VkDevice, DeviceDispatch> { | ||
| 671 | using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle; | ||
| 672 | |||
| 673 | public: | ||
| 674 | VkResult GetStatus() const noexcept { | ||
| 675 | return dld->vkGetEventStatus(owner, handle); | ||
| 676 | } | ||
| 677 | }; | ||
| 678 | |||
| 679 | class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> { | ||
| 680 | using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle; | ||
| 681 | |||
| 682 | public: | ||
| 683 | [[nodiscard]] u64 GetCounter() const { | ||
| 684 | u64 value; | ||
| 685 | Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value)); | ||
| 686 | return value; | ||
| 687 | } | ||
| 688 | |||
| 689 | /** | ||
| 690 | * Waits for a timeline semaphore on the host. | ||
| 691 | * | ||
| 692 | * @param value Value to wait | ||
| 693 | * @param timeout Time in nanoseconds to timeout | ||
| 694 | * @return True on successful wait, false on timeout | ||
| 695 | */ | ||
| 696 | bool Wait(u64 value, u64 timeout = std::numeric_limits<u64>::max()) const { | ||
| 697 | const VkSemaphoreWaitInfoKHR wait_info{ | ||
| 698 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR, | ||
| 699 | .pNext = nullptr, | ||
| 700 | .flags = 0, | ||
| 701 | .semaphoreCount = 1, | ||
| 702 | .pSemaphores = &handle, | ||
| 703 | .pValues = &value, | ||
| 704 | }; | ||
| 705 | const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout); | ||
| 706 | switch (result) { | ||
| 707 | case VK_SUCCESS: | ||
| 708 | return true; | ||
| 709 | case VK_TIMEOUT: | ||
| 710 | return false; | ||
| 711 | default: | ||
| 712 | throw Exception(result); | ||
| 713 | } | ||
| 714 | } | ||
| 715 | }; | ||
| 716 | |||
| 717 | class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> { | ||
| 718 | using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle; | ||
| 719 | |||
| 720 | public: | ||
| 721 | static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, | ||
| 722 | Span<const char*> enabled_extensions, const void* next, | ||
| 723 | DeviceDispatch& dld) noexcept; | ||
| 724 | |||
| 725 | Queue GetQueue(u32 family_index) const noexcept; | ||
| 726 | |||
| 727 | Buffer CreateBuffer(const VkBufferCreateInfo& ci) const; | ||
| 728 | |||
| 729 | BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; | ||
| 730 | |||
| 731 | Image CreateImage(const VkImageCreateInfo& ci) const; | ||
| 732 | |||
| 733 | ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; | ||
| 734 | |||
| 735 | Semaphore CreateSemaphore() const; | ||
| 736 | |||
| 737 | Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const; | ||
| 738 | |||
| 739 | Fence CreateFence(const VkFenceCreateInfo& ci) const; | ||
| 740 | |||
| 741 | DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; | ||
| 742 | |||
| 743 | RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const; | ||
| 744 | |||
| 745 | DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const; | ||
| 746 | |||
| 747 | PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const; | ||
| 748 | |||
| 749 | Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const; | ||
| 750 | |||
| 751 | Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const; | ||
| 752 | |||
| 753 | Sampler CreateSampler(const VkSamplerCreateInfo& ci) const; | ||
| 754 | |||
| 755 | Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const; | ||
| 756 | |||
| 757 | CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const; | ||
| 758 | |||
| 759 | DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR( | ||
| 760 | const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const; | ||
| 761 | |||
| 762 | QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const; | ||
| 763 | |||
| 764 | ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; | ||
| 765 | |||
| 766 | Event CreateEvent() const; | ||
| 767 | |||
| 768 | SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; | ||
| 769 | |||
| 770 | DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept; | ||
| 771 | |||
| 772 | DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const; | ||
| 773 | |||
| 774 | VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept; | ||
| 775 | |||
| 776 | VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept; | ||
| 777 | |||
| 778 | void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes, | ||
| 779 | Span<VkCopyDescriptorSet> copies) const noexcept; | ||
| 780 | |||
| 781 | void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template, | ||
| 782 | const void* data) const noexcept { | ||
| 783 | dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data); | ||
| 784 | } | ||
| 785 | |||
| 786 | VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore, | ||
| 787 | VkFence fence, u32* image_index) const noexcept { | ||
| 788 | return dld->vkAcquireNextImageKHR(handle, swapchain, timeout, semaphore, fence, | ||
| 789 | image_index); | ||
| 790 | } | ||
| 791 | |||
| 792 | VkResult WaitIdle() const noexcept { | ||
| 793 | return dld->vkDeviceWaitIdle(handle); | ||
| 794 | } | ||
| 795 | |||
| 796 | void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept { | ||
| 797 | dld->vkResetQueryPoolEXT(handle, query_pool, first, count); | ||
| 798 | } | ||
| 799 | |||
| 800 | VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size, | ||
| 801 | void* data, VkDeviceSize stride, | ||
| 802 | VkQueryResultFlags flags) const noexcept { | ||
| 803 | return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride, | ||
| 804 | flags); | ||
| 805 | } | ||
| 806 | }; | ||
| 807 | |||
| 808 | class PhysicalDevice { | ||
| 809 | public: | ||
| 810 | constexpr PhysicalDevice() noexcept = default; | ||
| 811 | |||
| 812 | constexpr PhysicalDevice(VkPhysicalDevice physical_device, const InstanceDispatch& dld) noexcept | ||
| 813 | : physical_device{physical_device}, dld{&dld} {} | ||
| 814 | |||
| 815 | constexpr operator VkPhysicalDevice() const noexcept { | ||
| 816 | return physical_device; | ||
| 817 | } | ||
| 818 | |||
| 819 | VkPhysicalDeviceProperties GetProperties() const noexcept; | ||
| 820 | |||
| 821 | void GetProperties2KHR(VkPhysicalDeviceProperties2KHR&) const noexcept; | ||
| 822 | |||
| 823 | VkPhysicalDeviceFeatures GetFeatures() const noexcept; | ||
| 824 | |||
| 825 | void GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR&) const noexcept; | ||
| 826 | |||
| 827 | VkFormatProperties GetFormatProperties(VkFormat) const noexcept; | ||
| 828 | |||
| 829 | std::vector<VkExtensionProperties> EnumerateDeviceExtensionProperties() const; | ||
| 830 | |||
| 831 | std::vector<VkQueueFamilyProperties> GetQueueFamilyProperties() const; | ||
| 832 | |||
| 833 | bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const; | ||
| 834 | |||
| 835 | VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const; | ||
| 836 | |||
| 837 | std::vector<VkSurfaceFormatKHR> GetSurfaceFormatsKHR(VkSurfaceKHR) const; | ||
| 838 | |||
| 839 | std::vector<VkPresentModeKHR> GetSurfacePresentModesKHR(VkSurfaceKHR) const; | ||
| 840 | |||
| 841 | VkPhysicalDeviceMemoryProperties GetMemoryProperties() const noexcept; | ||
| 842 | |||
| 843 | private: | ||
| 844 | VkPhysicalDevice physical_device = nullptr; | ||
| 845 | const InstanceDispatch* dld = nullptr; | ||
| 846 | }; | ||
| 847 | |||
| 848 | class CommandBuffer { | ||
| 849 | public: | ||
| 850 | CommandBuffer() noexcept = default; | ||
| 851 | |||
| 852 | explicit CommandBuffer(VkCommandBuffer handle, const DeviceDispatch& dld) noexcept | ||
| 853 | : handle{handle}, dld{&dld} {} | ||
| 854 | |||
| 855 | const VkCommandBuffer* address() const noexcept { | ||
| 856 | return &handle; | ||
| 857 | } | ||
| 858 | |||
| 859 | void Begin(const VkCommandBufferBeginInfo& begin_info) const { | ||
| 860 | Check(dld->vkBeginCommandBuffer(handle, &begin_info)); | ||
| 861 | } | ||
| 862 | |||
| 863 | void End() const { | ||
| 864 | Check(dld->vkEndCommandBuffer(handle)); | ||
| 865 | } | ||
| 866 | |||
| 867 | void BeginRenderPass(const VkRenderPassBeginInfo& renderpass_bi, | ||
| 868 | VkSubpassContents contents) const noexcept { | ||
| 869 | dld->vkCmdBeginRenderPass(handle, &renderpass_bi, contents); | ||
| 870 | } | ||
| 871 | |||
| 872 | void EndRenderPass() const noexcept { | ||
| 873 | dld->vkCmdEndRenderPass(handle); | ||
| 874 | } | ||
| 875 | |||
| 876 | void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept { | ||
| 877 | dld->vkCmdBeginQuery(handle, query_pool, query, flags); | ||
| 878 | } | ||
| 879 | |||
| 880 | void EndQuery(VkQueryPool query_pool, u32 query) const noexcept { | ||
| 881 | dld->vkCmdEndQuery(handle, query_pool, query); | ||
| 882 | } | ||
| 883 | |||
| 884 | void BindDescriptorSets(VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 first, | ||
| 885 | Span<VkDescriptorSet> sets, Span<u32> dynamic_offsets) const noexcept { | ||
| 886 | dld->vkCmdBindDescriptorSets(handle, bind_point, layout, first, sets.size(), sets.data(), | ||
| 887 | dynamic_offsets.size(), dynamic_offsets.data()); | ||
| 888 | } | ||
| 889 | |||
| 890 | void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept { | ||
| 891 | dld->vkCmdBindPipeline(handle, bind_point, pipeline); | ||
| 892 | } | ||
| 893 | |||
| 894 | void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, | ||
| 895 | VkIndexType index_type) const noexcept { | ||
| 896 | dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type); | ||
| 897 | } | ||
| 898 | |||
| 899 | void BindVertexBuffers(u32 first, u32 count, const VkBuffer* buffers, | ||
| 900 | const VkDeviceSize* offsets) const noexcept { | ||
| 901 | dld->vkCmdBindVertexBuffers(handle, first, count, buffers, offsets); | ||
| 902 | } | ||
| 903 | |||
| 904 | void BindVertexBuffer(u32 binding, VkBuffer buffer, VkDeviceSize offset) const noexcept { | ||
| 905 | BindVertexBuffers(binding, 1, &buffer, &offset); | ||
| 906 | } | ||
| 907 | |||
| 908 | void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex, | ||
| 909 | u32 first_instance) const noexcept { | ||
| 910 | dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance); | ||
| 911 | } | ||
| 912 | |||
| 913 | void DrawIndexed(u32 index_count, u32 instance_count, u32 first_index, u32 vertex_offset, | ||
| 914 | u32 first_instance) const noexcept { | ||
| 915 | dld->vkCmdDrawIndexed(handle, index_count, instance_count, first_index, vertex_offset, | ||
| 916 | first_instance); | ||
| 917 | } | ||
| 918 | |||
| 919 | void ClearAttachments(Span<VkClearAttachment> attachments, | ||
| 920 | Span<VkClearRect> rects) const noexcept { | ||
| 921 | dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), | ||
| 922 | rects.data()); | ||
| 923 | } | ||
| 924 | |||
| 925 | void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, | ||
| 926 | VkImageLayout dst_layout, Span<VkImageBlit> regions, | ||
| 927 | VkFilter filter) const noexcept { | ||
| 928 | dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), | ||
| 929 | regions.data(), filter); | ||
| 930 | } | ||
| 931 | |||
| 932 | void Dispatch(u32 x, u32 y, u32 z) const noexcept { | ||
| 933 | dld->vkCmdDispatch(handle, x, y, z); | ||
| 934 | } | ||
| 935 | |||
| 936 | void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, | ||
| 937 | VkDependencyFlags dependency_flags, Span<VkMemoryBarrier> memory_barriers, | ||
| 938 | Span<VkBufferMemoryBarrier> buffer_barriers, | ||
| 939 | Span<VkImageMemoryBarrier> image_barriers) const noexcept { | ||
| 940 | dld->vkCmdPipelineBarrier(handle, src_stage_mask, dst_stage_mask, dependency_flags, | ||
| 941 | memory_barriers.size(), memory_barriers.data(), | ||
| 942 | buffer_barriers.size(), buffer_barriers.data(), | ||
| 943 | image_barriers.size(), image_barriers.data()); | ||
| 944 | } | ||
| 945 | |||
| 946 | void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout, | ||
| 947 | Span<VkBufferImageCopy> regions) const noexcept { | ||
| 948 | dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(), | ||
| 949 | regions.data()); | ||
| 950 | } | ||
| 951 | |||
| 952 | void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, | ||
| 953 | Span<VkBufferCopy> regions) const noexcept { | ||
| 954 | dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data()); | ||
| 955 | } | ||
| 956 | |||
| 957 | void CopyImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, | ||
| 958 | VkImageLayout dst_layout, Span<VkImageCopy> regions) const noexcept { | ||
| 959 | dld->vkCmdCopyImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), | ||
| 960 | regions.data()); | ||
| 961 | } | ||
| 962 | |||
| 963 | void CopyImageToBuffer(VkImage src_image, VkImageLayout src_layout, VkBuffer dst_buffer, | ||
| 964 | Span<VkBufferImageCopy> regions) const noexcept { | ||
| 965 | dld->vkCmdCopyImageToBuffer(handle, src_image, src_layout, dst_buffer, regions.size(), | ||
| 966 | regions.data()); | ||
| 967 | } | ||
| 968 | |||
| 969 | void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size, | ||
| 970 | u32 data) const noexcept { | ||
| 971 | dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data); | ||
| 972 | } | ||
| 973 | |||
| 974 | void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, u32 offset, u32 size, | ||
| 975 | const void* values) const noexcept { | ||
| 976 | dld->vkCmdPushConstants(handle, layout, flags, offset, size, values); | ||
| 977 | } | ||
| 978 | |||
| 979 | void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept { | ||
| 980 | dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data()); | ||
| 981 | } | ||
| 982 | |||
| 983 | void SetScissor(u32 first, Span<VkRect2D> scissors) const noexcept { | ||
| 984 | dld->vkCmdSetScissor(handle, first, scissors.size(), scissors.data()); | ||
| 985 | } | ||
| 986 | |||
| 987 | void SetBlendConstants(const float blend_constants[4]) const noexcept { | ||
| 988 | dld->vkCmdSetBlendConstants(handle, blend_constants); | ||
| 989 | } | ||
| 990 | |||
| 991 | void SetStencilCompareMask(VkStencilFaceFlags face_mask, u32 compare_mask) const noexcept { | ||
| 992 | dld->vkCmdSetStencilCompareMask(handle, face_mask, compare_mask); | ||
| 993 | } | ||
| 994 | |||
| 995 | void SetStencilReference(VkStencilFaceFlags face_mask, u32 reference) const noexcept { | ||
| 996 | dld->vkCmdSetStencilReference(handle, face_mask, reference); | ||
| 997 | } | ||
| 998 | |||
| 999 | void SetStencilWriteMask(VkStencilFaceFlags face_mask, u32 write_mask) const noexcept { | ||
| 1000 | dld->vkCmdSetStencilWriteMask(handle, face_mask, write_mask); | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | void SetDepthBias(float constant_factor, float clamp, float slope_factor) const noexcept { | ||
| 1004 | dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor); | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept { | ||
| 1008 | dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | void SetEvent(VkEvent event, VkPipelineStageFlags stage_flags) const noexcept { | ||
| 1012 | dld->vkCmdSetEvent(handle, event, stage_flags); | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | void WaitEvents(Span<VkEvent> events, VkPipelineStageFlags src_stage_mask, | ||
| 1016 | VkPipelineStageFlags dst_stage_mask, Span<VkMemoryBarrier> memory_barriers, | ||
| 1017 | Span<VkBufferMemoryBarrier> buffer_barriers, | ||
| 1018 | Span<VkImageMemoryBarrier> image_barriers) const noexcept { | ||
| 1019 | dld->vkCmdWaitEvents(handle, events.size(), events.data(), src_stage_mask, dst_stage_mask, | ||
| 1020 | memory_barriers.size(), memory_barriers.data(), buffer_barriers.size(), | ||
| 1021 | buffer_barriers.data(), image_barriers.size(), image_barriers.data()); | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | void BindVertexBuffers2EXT(u32 first_binding, u32 binding_count, const VkBuffer* buffers, | ||
| 1025 | const VkDeviceSize* offsets, const VkDeviceSize* sizes, | ||
| 1026 | const VkDeviceSize* strides) const noexcept { | ||
| 1027 | dld->vkCmdBindVertexBuffers2EXT(handle, first_binding, binding_count, buffers, offsets, | ||
| 1028 | sizes, strides); | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | void SetCullModeEXT(VkCullModeFlags cull_mode) const noexcept { | ||
| 1032 | dld->vkCmdSetCullModeEXT(handle, cull_mode); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | void SetDepthBoundsTestEnableEXT(bool enable) const noexcept { | ||
| 1036 | dld->vkCmdSetDepthBoundsTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | void SetDepthCompareOpEXT(VkCompareOp compare_op) const noexcept { | ||
| 1040 | dld->vkCmdSetDepthCompareOpEXT(handle, compare_op); | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | void SetDepthTestEnableEXT(bool enable) const noexcept { | ||
| 1044 | dld->vkCmdSetDepthTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | void SetDepthWriteEnableEXT(bool enable) const noexcept { | ||
| 1048 | dld->vkCmdSetDepthWriteEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | void SetFrontFaceEXT(VkFrontFace front_face) const noexcept { | ||
| 1052 | dld->vkCmdSetFrontFaceEXT(handle, front_face); | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | void SetPrimitiveTopologyEXT(VkPrimitiveTopology primitive_topology) const noexcept { | ||
| 1056 | dld->vkCmdSetPrimitiveTopologyEXT(handle, primitive_topology); | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | void SetStencilOpEXT(VkStencilFaceFlags face_mask, VkStencilOp fail_op, VkStencilOp pass_op, | ||
| 1060 | VkStencilOp depth_fail_op, VkCompareOp compare_op) const noexcept { | ||
| 1061 | dld->vkCmdSetStencilOpEXT(handle, face_mask, fail_op, pass_op, depth_fail_op, compare_op); | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | void SetStencilTestEnableEXT(bool enable) const noexcept { | ||
| 1065 | dld->vkCmdSetStencilTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers, | ||
| 1069 | const VkDeviceSize* offsets, | ||
| 1070 | const VkDeviceSize* sizes) const noexcept { | ||
| 1071 | dld->vkCmdBindTransformFeedbackBuffersEXT(handle, first, count, buffers, offsets, sizes); | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | void BeginTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count, | ||
| 1075 | const VkBuffer* counter_buffers, | ||
| 1076 | const VkDeviceSize* counter_buffer_offsets) const noexcept { | ||
| 1077 | dld->vkCmdBeginTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count, | ||
| 1078 | counter_buffers, counter_buffer_offsets); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | void EndTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count, | ||
| 1082 | const VkBuffer* counter_buffers, | ||
| 1083 | const VkDeviceSize* counter_buffer_offsets) const noexcept { | ||
| 1084 | dld->vkCmdEndTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count, | ||
| 1085 | counter_buffers, counter_buffer_offsets); | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | private: | ||
| 1089 | VkCommandBuffer handle; | ||
| 1090 | const DeviceDispatch* dld; | ||
| 1091 | }; | ||
| 1092 | |||
| 1093 | std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( | ||
| 1094 | const InstanceDispatch& dld); | ||
| 1095 | |||
| 1096 | std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties( | ||
| 1097 | const InstanceDispatch& dld); | ||
| 1098 | |||
| 1099 | } // namespace Vulkan::vk | ||