diff options
| author | 2020-12-30 02:25:23 -0300 | |
|---|---|---|
| committer | 2020-12-30 03:38:50 -0300 | |
| commit | 9764c13d6d2977903f407761b27d847c0056e1c4 (patch) | |
| tree | f6f5d6d6379b0404147969e7d1f548ed3d49ca01 /src/video_core/renderer_vulkan | |
| parent | video_core: Add a delayed destruction ring abstraction (diff) | |
| download | yuzu-9764c13d6d2977903f407761b27d847c0056e1c4.tar.gz yuzu-9764c13d6d2977903f407761b27d847c0056e1c4.tar.xz yuzu-9764c13d6d2977903f407761b27d847c0056e1c4.zip | |
video_core: Rewrite the texture cache
The current texture cache has several points that hurt maintainability
and performance. It's easy to break unrelated parts of the cache
when doing minor changes. The cache can easily forget valuable
information about the cached textures by CPU writes or simply by its
normal usage.The current texture cache has several points that hurt
maintainability and performance. It's easy to break unrelated parts
of the cache when doing minor changes. The cache can easily forget
valuable information about the cached textures by CPU writes or simply
by its normal usage.
This commit aims to address those issues.
Diffstat (limited to 'src/video_core/renderer_vulkan')
52 files changed, 2979 insertions, 2582 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..87c8e5693 --- /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_device.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 16 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 17 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | ||
| 18 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | ||
| 19 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | ||
| 20 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 21 | #include "video_core/surface.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 VKDevice& 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 VKDevice& 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 VKDevice& 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..2c2790bf9 --- /dev/null +++ b/src/video_core/renderer_vulkan/blit_image.h | |||
| @@ -0,0 +1,97 @@ | |||
| 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/renderer_vulkan/wrapper.h" | ||
| 12 | #include "video_core/texture_cache/types.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | using VideoCommon::Offset2D; | ||
| 17 | |||
| 18 | class VKDevice; | ||
| 19 | class VKScheduler; | ||
| 20 | class StateTracker; | ||
| 21 | |||
| 22 | class Framebuffer; | ||
| 23 | class ImageView; | ||
| 24 | |||
| 25 | struct BlitImagePipelineKey { | ||
| 26 | constexpr auto operator<=>(const BlitImagePipelineKey&) const noexcept = default; | ||
| 27 | |||
| 28 | VkRenderPass renderpass; | ||
| 29 | Tegra::Engines::Fermi2D::Operation operation; | ||
| 30 | }; | ||
| 31 | |||
| 32 | class BlitImageHelper { | ||
| 33 | public: | ||
| 34 | explicit BlitImageHelper(const VKDevice& device, VKScheduler& scheduler, | ||
| 35 | StateTracker& state_tracker, VKDescriptorPool& descriptor_pool); | ||
| 36 | ~BlitImageHelper(); | ||
| 37 | |||
| 38 | void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | ||
| 39 | const std::array<Offset2D, 2>& dst_region, | ||
| 40 | const std::array<Offset2D, 2>& src_region, | ||
| 41 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 42 | Tegra::Engines::Fermi2D::Operation operation); | ||
| 43 | |||
| 44 | void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, | ||
| 45 | VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region, | ||
| 46 | const std::array<Offset2D, 2>& src_region, | ||
| 47 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 48 | Tegra::Engines::Fermi2D::Operation operation); | ||
| 49 | |||
| 50 | void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | ||
| 51 | |||
| 52 | void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | ||
| 53 | |||
| 54 | void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | ||
| 55 | |||
| 56 | void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); | ||
| 57 | |||
| 58 | private: | ||
| 59 | void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | ||
| 60 | const ImageView& src_image_view); | ||
| 61 | |||
| 62 | [[nodiscard]] VkPipeline FindOrEmplacePipeline(const BlitImagePipelineKey& key); | ||
| 63 | |||
| 64 | [[nodiscard]] VkPipeline BlitDepthStencilPipeline(VkRenderPass renderpass); | ||
| 65 | |||
| 66 | void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); | ||
| 67 | |||
| 68 | void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); | ||
| 69 | |||
| 70 | const VKDevice& device; | ||
| 71 | VKScheduler& scheduler; | ||
| 72 | StateTracker& state_tracker; | ||
| 73 | |||
| 74 | vk::DescriptorSetLayout one_texture_set_layout; | ||
| 75 | vk::DescriptorSetLayout two_textures_set_layout; | ||
| 76 | DescriptorAllocator one_texture_descriptor_allocator; | ||
| 77 | DescriptorAllocator two_textures_descriptor_allocator; | ||
| 78 | vk::PipelineLayout one_texture_pipeline_layout; | ||
| 79 | vk::PipelineLayout two_textures_pipeline_layout; | ||
| 80 | vk::ShaderModule full_screen_vert; | ||
| 81 | vk::ShaderModule blit_color_to_color_frag; | ||
| 82 | vk::ShaderModule blit_depth_stencil_frag; | ||
| 83 | vk::ShaderModule convert_depth_to_float_frag; | ||
| 84 | vk::ShaderModule convert_float_to_depth_frag; | ||
| 85 | vk::Sampler linear_sampler; | ||
| 86 | vk::Sampler nearest_sampler; | ||
| 87 | |||
| 88 | std::vector<BlitImagePipelineKey> blit_color_keys; | ||
| 89 | std::vector<vk::Pipeline> blit_color_pipelines; | ||
| 90 | vk::Pipeline blit_depth_stencil_pipeline; | ||
| 91 | vk::Pipeline convert_d32_to_r32_pipeline; | ||
| 92 | vk::Pipeline convert_r32_to_d32_pipeline; | ||
| 93 | vk::Pipeline convert_d16_to_r16_pipeline; | ||
| 94 | vk::Pipeline convert_r16_to_d16_pipeline; | ||
| 95 | }; | ||
| 96 | |||
| 97 | } // 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 5ec43db11..67dd10500 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | |||
| @@ -60,6 +60,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta | |||
| 60 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); | 60 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); |
| 61 | 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); | 62 | topology.Assign(regs.draw.topology); |
| 63 | msaa_mode.Assign(regs.multisample_mode); | ||
| 63 | 64 | ||
| 64 | raw2 = 0; | 65 | raw2 = 0; |
| 65 | const auto test_func = | 66 | const auto test_func = |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index c26b77790..7e95e6fce 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h | |||
| @@ -186,6 +186,7 @@ struct FixedPipelineState { | |||
| 186 | BitField<19, 4, u32> logic_op; | 186 | BitField<19, 4, u32> logic_op; |
| 187 | BitField<23, 1, u32> rasterize_enable; | 187 | BitField<23, 1, u32> rasterize_enable; |
| 188 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; | 188 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; |
| 189 | BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode; | ||
| 189 | }; | 190 | }; |
| 190 | union { | 191 | union { |
| 191 | u32 raw2; | 192 | u32 raw2; |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 58e117eb3..40501e7fa 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -122,7 +122,7 @@ struct FormatTuple { | |||
| 122 | {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT | 122 | {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT |
| 123 | {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT | 123 | {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT |
| 124 | {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM | 124 | {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM |
| 125 | {VK_FORMAT_B5G6R5_UNORM_PACK16, Attachable}, // B5G6R5_UNORM | 125 | {VK_FORMAT_B5G6R5_UNORM_PACK16}, // B5G6R5_UNORM |
| 126 | {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM | 126 | {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM |
| 127 | {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM | 127 | {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM |
| 128 | {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT | 128 | {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT |
| @@ -163,7 +163,7 @@ struct FormatTuple { | |||
| 163 | {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM | 163 | {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM |
| 164 | {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT | 164 | {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT |
| 165 | {VK_FORMAT_UNDEFINED}, // R16G16_UINT | 165 | {VK_FORMAT_UNDEFINED}, // R16G16_UINT |
| 166 | {VK_FORMAT_UNDEFINED}, // R16G16_SINT | 166 | {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT |
| 167 | {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM | 167 | {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM |
| 168 | {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT | 168 | {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT |
| 169 | {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB | 169 | {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB |
| @@ -233,18 +233,20 @@ FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFo | |||
| 233 | 233 | ||
| 234 | // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively | 234 | // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively |
| 235 | if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { | 235 | if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { |
| 236 | tuple.format = VideoCore::Surface::IsPixelFormatSRGB(pixel_format) | 236 | const bool is_srgb = VideoCore::Surface::IsPixelFormatSRGB(pixel_format); |
| 237 | ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 | 237 | tuple.format = is_srgb ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 : VK_FORMAT_A8B8G8R8_UNORM_PACK32; |
| 238 | : VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 239 | } | 238 | } |
| 240 | const bool attachable = tuple.usage & Attachable; | 239 | const bool attachable = tuple.usage & Attachable; |
| 241 | const bool storage = tuple.usage & Storage; | 240 | const bool storage = tuple.usage & Storage; |
| 242 | 241 | ||
| 243 | VkFormatFeatureFlags usage; | 242 | VkFormatFeatureFlags usage; |
| 244 | if (format_type == FormatType::Buffer) { | 243 | switch (format_type) { |
| 244 | case FormatType::Buffer: | ||
| 245 | usage = | 245 | usage = |
| 246 | 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; |
| 247 | } else { | 247 | break; |
| 248 | case FormatType::Linear: | ||
| 249 | case FormatType::Optimal: | ||
| 248 | 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 | |
| 249 | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT; | 251 | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT; |
| 250 | if (attachable) { | 252 | if (attachable) { |
| @@ -254,6 +256,7 @@ FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFo | |||
| 254 | if (storage) { | 256 | if (storage) { |
| 255 | usage |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; | 257 | usage |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; |
| 256 | } | 258 | } |
| 259 | break; | ||
| 257 | } | 260 | } |
| 258 | return {device.GetSupportedFormat(tuple.format, usage, format_type), attachable, storage}; | 261 | return {device.GetSupportedFormat(tuple.format, usage, format_type), attachable, storage}; |
| 259 | } | 262 | } |
| @@ -724,4 +727,17 @@ VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle) | |||
| 724 | return {}; | 727 | return {}; |
| 725 | } | 728 | } |
| 726 | 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 | |||
| 727 | } // 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..1a90f192e 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.h +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h | |||
| @@ -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/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index ea4b7c1e6..7f521cb9b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -92,9 +92,9 @@ Common::DynamicLibrary OpenVulkanLibrary() { | |||
| 92 | return library; | 92 | return library; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | std::pair<vk::Instance, u32> CreateInstance( | 95 | std::pair<vk::Instance, u32> CreateInstance(Common::DynamicLibrary& library, |
| 96 | Common::DynamicLibrary& library, vk::InstanceDispatch& dld, | 96 | vk::InstanceDispatch& dld, WindowSystemType window_type, |
| 97 | WindowSystemType window_type = WindowSystemType::Headless, bool enable_layers = false) { | 97 | bool enable_debug_utils, bool enable_layers) { |
| 98 | if (!library.IsOpen()) { | 98 | if (!library.IsOpen()) { |
| 99 | LOG_ERROR(Render_Vulkan, "Vulkan library not available"); | 99 | LOG_ERROR(Render_Vulkan, "Vulkan library not available"); |
| 100 | return {}; | 100 | return {}; |
| @@ -133,7 +133,7 @@ std::pair<vk::Instance, u32> CreateInstance( | |||
| 133 | if (window_type != Core::Frontend::WindowSystemType::Headless) { | 133 | if (window_type != Core::Frontend::WindowSystemType::Headless) { |
| 134 | extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); | 134 | extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); |
| 135 | } | 135 | } |
| 136 | if (enable_layers) { | 136 | if (enable_debug_utils) { |
| 137 | extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); | 137 | extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| 138 | } | 138 | } |
| 139 | extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); | 139 | extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| @@ -287,7 +287,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 287 | bool RendererVulkan::Init() { | 287 | bool RendererVulkan::Init() { |
| 288 | library = OpenVulkanLibrary(); | 288 | library = OpenVulkanLibrary(); |
| 289 | std::tie(instance, instance_version) = CreateInstance( | 289 | std::tie(instance, instance_version) = CreateInstance( |
| 290 | library, dld, render_window.GetWindowInfo().type, Settings::values.renderer_debug); | 290 | library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug); |
| 291 | if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { | 291 | if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { |
| 292 | return false; | 292 | return false; |
| 293 | } | 293 | } |
| @@ -447,7 +447,8 @@ void RendererVulkan::Report() const { | |||
| 447 | std::vector<std::string> RendererVulkan::EnumerateDevices() { | 447 | std::vector<std::string> RendererVulkan::EnumerateDevices() { |
| 448 | vk::InstanceDispatch dld; | 448 | vk::InstanceDispatch dld; |
| 449 | Common::DynamicLibrary library = OpenVulkanLibrary(); | 449 | Common::DynamicLibrary library = OpenVulkanLibrary(); |
| 450 | vk::Instance instance = CreateInstance(library, dld).first; | 450 | vk::Instance instance = |
| 451 | CreateInstance(library, dld, WindowSystemType::Headless, false, false).first; | ||
| 451 | if (!instance) { | 452 | if (!instance) { |
| 452 | return {}; | 453 | return {}; |
| 453 | } | 454 | } |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 977b86003..74642fba4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -33,10 +33,9 @@ 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{}; |
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..d3a83f22f 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -16,12 +16,12 @@ | |||
| 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_device.h" |
| 24 | #include "video_core/renderer_vulkan/vk_image.h" | ||
| 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 26 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 26 | #include "video_core/renderer_vulkan/vk_memory_manager.h" |
| 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| @@ -29,108 +29,12 @@ | |||
| 29 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 29 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 30 | #include "video_core/renderer_vulkan/wrapper.h" | 30 | #include "video_core/renderer_vulkan/wrapper.h" |
| 31 | #include "video_core/surface.h" | 31 | #include "video_core/surface.h" |
| 32 | #include "video_core/textures/decoders.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) { |
| @@ -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..2ee374247 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -35,7 +35,6 @@ struct ScreenInfo; | |||
| 35 | 35 | ||
| 36 | class RasterizerVulkan; | 36 | class RasterizerVulkan; |
| 37 | class VKDevice; | 37 | class VKDevice; |
| 38 | class VKImage; | ||
| 39 | class VKScheduler; | 38 | class VKScheduler; |
| 40 | class VKSwapchain; | 39 | class VKSwapchain; |
| 41 | 40 | ||
| @@ -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 444d3fb93..10d296c2f 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -31,15 +31,19 @@ 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 | constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS = | ||
| 35 | VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT; | ||
| 36 | |||
| 34 | std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKScheduler& scheduler) { | 37 | std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKScheduler& scheduler) { |
| 35 | return std::make_unique<VKStreamBuffer>(device, scheduler, BUFFER_USAGE); | 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 VKDevice& 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, |
| @@ -64,24 +68,39 @@ void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { | |||
| 64 | scheduler.RequestOutsideRenderPassOperationContext(); | 68 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 65 | 69 | ||
| 66 | const VkBuffer handle = Handle(); | 70 | const VkBuffer handle = Handle(); |
| 67 | scheduler.Record( | 71 | scheduler.Record([staging = *staging.handle, handle, offset, data_size, |
| 68 | [staging = *staging.handle, handle, offset, data_size](vk::CommandBuffer cmdbuf) { | 72 | &device = device](vk::CommandBuffer cmdbuf) { |
| 69 | cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, data_size}); | 73 | const VkBufferMemoryBarrier read_barrier{ |
| 70 | 74 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | |
| 71 | const VkBufferMemoryBarrier barrier{ | 75 | .pNext = nullptr, |
| 72 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 76 | .srcAccessMask = |
| 73 | .pNext = nullptr, | 77 | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | |
| 74 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | 78 | VK_ACCESS_HOST_WRITE_BIT | |
| 75 | .dstAccessMask = UPLOAD_ACCESS_BARRIERS, | 79 | (device.IsExtTransformFeedbackSupported() ? TRANSFORM_FEEDBACK_WRITE_ACCESS : 0), |
| 76 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 80 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, |
| 77 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 81 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 78 | .buffer = handle, | 82 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 79 | .offset = offset, | 83 | .buffer = handle, |
| 80 | .size = data_size, | 84 | .offset = offset, |
| 81 | }; | 85 | .size = data_size, |
| 82 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, | 86 | }; |
| 83 | barrier, {}); | 87 | const VkBufferMemoryBarrier write_barrier{ |
| 84 | }); | 88 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| 89 | .pNext = nullptr, | ||
| 90 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 91 | .dstAccessMask = UPLOAD_ACCESS_BARRIERS, | ||
| 92 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 93 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 94 | .buffer = handle, | ||
| 95 | .offset = offset, | ||
| 96 | .size = data_size, | ||
| 97 | }; | ||
| 98 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 99 | 0, read_barrier); | ||
| 100 | cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, data_size}); | ||
| 101 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, | ||
| 102 | write_barrier); | ||
| 103 | }); | ||
| 85 | } | 104 | } |
| 86 | 105 | ||
| 87 | void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { | 106 | void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { |
| @@ -150,8 +169,10 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst | |||
| 150 | VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, | 169 | VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, |
| 151 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, | 170 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, |
| 152 | const VKDevice& device_, VKMemoryManager& memory_manager_, | 171 | const VKDevice& device_, VKMemoryManager& memory_manager_, |
| 153 | VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_) | 172 | VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, |
| 154 | : BufferCache{rasterizer_, gpu_memory_, cpu_memory_, CreateStreamBuffer(device_, scheduler_)}, | 173 | VKStagingBufferPool& staging_pool_) |
| 174 | : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_, | ||
| 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 6008b8373..daf498222 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -41,6 +41,7 @@ public: | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | private: | 43 | private: |
| 44 | const VKDevice& device; | ||
| 44 | VKScheduler& scheduler; | 45 | VKScheduler& scheduler; |
| 45 | VKStagingBufferPool& staging_pool; | 46 | VKStagingBufferPool& staging_pool; |
| 46 | 47 | ||
| @@ -49,10 +50,11 @@ private: | |||
| 49 | 50 | ||
| 50 | class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { | 51 | class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { |
| 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 VKDevice& 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; |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 1ac7e2a30..2c030e910 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp | |||
| @@ -10,6 +10,9 @@ | |||
| 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" | 18 | #include "video_core/renderer_vulkan/vk_device.h" |
| @@ -22,99 +25,6 @@ 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 | { |
| @@ -381,8 +89,8 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() { | |||
| 381 | VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool, | 89 | VKComputePass::VKComputePass(const VKDevice& 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, |
| @@ -467,7 +168,7 @@ QuadArrayPass::QuadArrayPass(const VKDevice& device_, VKScheduler& scheduler_, | |||
| 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 | ||
| @@ -510,12 +211,11 @@ 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 VKDevice& 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), | ||
| 519 | scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, | 219 | scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, |
| 520 | update_descriptor_queue{update_descriptor_queue_} {} | 220 | update_descriptor_queue{update_descriptor_queue_} {} |
| 521 | 221 | ||
| @@ -561,8 +261,7 @@ QuadIndexedPass::QuadIndexedPass(const VKDevice& device_, VKScheduler& scheduler | |||
| 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), | ||
| 566 | scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, | 265 | scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, |
| 567 | update_descriptor_queue{update_descriptor_queue_} {} | 266 | update_descriptor_queue{update_descriptor_queue_} {} |
| 568 | 267 | ||
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index 2dc87902c..abdf61e2c 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h | |||
| @@ -5,6 +5,7 @@ | |||
| 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" |
| @@ -24,8 +25,7 @@ public: | |||
| 24 | explicit VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool, | 25 | explicit VKComputePass(const VKDevice& 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: |
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index ce3846195..370a63f74 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp | |||
| @@ -46,6 +46,7 @@ constexpr std::array REQUIRED_EXTENSIONS{ | |||
| 46 | VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, | 46 | VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, |
| 47 | VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, | 47 | VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, |
| 48 | VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, | 48 | VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, |
| 49 | VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, | ||
| 49 | VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, | 50 | VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, |
| 50 | VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, | 51 | VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, |
| 51 | VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, | 52 | VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, |
| @@ -122,6 +123,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( | |||
| 122 | VK_FORMAT_R16G16_UNORM, | 123 | VK_FORMAT_R16G16_UNORM, |
| 123 | VK_FORMAT_R16G16_SNORM, | 124 | VK_FORMAT_R16G16_SNORM, |
| 124 | VK_FORMAT_R16G16_SFLOAT, | 125 | VK_FORMAT_R16G16_SFLOAT, |
| 126 | VK_FORMAT_R16G16_SINT, | ||
| 125 | VK_FORMAT_R16_UNORM, | 127 | VK_FORMAT_R16_UNORM, |
| 126 | VK_FORMAT_R16_UINT, | 128 | VK_FORMAT_R16_UINT, |
| 127 | VK_FORMAT_R8G8B8A8_SRGB, | 129 | VK_FORMAT_R8G8B8A8_SRGB, |
| @@ -161,18 +163,32 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( | |||
| 161 | VK_FORMAT_BC2_SRGB_BLOCK, | 163 | VK_FORMAT_BC2_SRGB_BLOCK, |
| 162 | VK_FORMAT_BC3_SRGB_BLOCK, | 164 | VK_FORMAT_BC3_SRGB_BLOCK, |
| 163 | VK_FORMAT_BC7_SRGB_BLOCK, | 165 | VK_FORMAT_BC7_SRGB_BLOCK, |
| 166 | VK_FORMAT_ASTC_4x4_UNORM_BLOCK, | ||
| 164 | VK_FORMAT_ASTC_4x4_SRGB_BLOCK, | 167 | VK_FORMAT_ASTC_4x4_SRGB_BLOCK, |
| 165 | VK_FORMAT_ASTC_8x8_SRGB_BLOCK, | 168 | VK_FORMAT_ASTC_5x4_UNORM_BLOCK, |
| 166 | VK_FORMAT_ASTC_8x5_SRGB_BLOCK, | ||
| 167 | VK_FORMAT_ASTC_5x4_SRGB_BLOCK, | 169 | VK_FORMAT_ASTC_5x4_SRGB_BLOCK, |
| 168 | VK_FORMAT_ASTC_5x5_UNORM_BLOCK, | 170 | VK_FORMAT_ASTC_5x5_UNORM_BLOCK, |
| 169 | VK_FORMAT_ASTC_5x5_SRGB_BLOCK, | 171 | VK_FORMAT_ASTC_5x5_SRGB_BLOCK, |
| 170 | VK_FORMAT_ASTC_10x8_UNORM_BLOCK, | 172 | VK_FORMAT_ASTC_6x5_UNORM_BLOCK, |
| 171 | VK_FORMAT_ASTC_10x8_SRGB_BLOCK, | 173 | VK_FORMAT_ASTC_6x5_SRGB_BLOCK, |
| 172 | VK_FORMAT_ASTC_6x6_UNORM_BLOCK, | 174 | VK_FORMAT_ASTC_6x6_UNORM_BLOCK, |
| 173 | VK_FORMAT_ASTC_6x6_SRGB_BLOCK, | 175 | VK_FORMAT_ASTC_6x6_SRGB_BLOCK, |
| 176 | VK_FORMAT_ASTC_8x5_UNORM_BLOCK, | ||
| 177 | VK_FORMAT_ASTC_8x5_SRGB_BLOCK, | ||
| 178 | VK_FORMAT_ASTC_8x6_UNORM_BLOCK, | ||
| 179 | VK_FORMAT_ASTC_8x6_SRGB_BLOCK, | ||
| 180 | VK_FORMAT_ASTC_8x8_UNORM_BLOCK, | ||
| 181 | VK_FORMAT_ASTC_8x8_SRGB_BLOCK, | ||
| 182 | VK_FORMAT_ASTC_10x5_UNORM_BLOCK, | ||
| 183 | VK_FORMAT_ASTC_10x5_SRGB_BLOCK, | ||
| 184 | VK_FORMAT_ASTC_10x6_UNORM_BLOCK, | ||
| 185 | VK_FORMAT_ASTC_10x6_SRGB_BLOCK, | ||
| 186 | VK_FORMAT_ASTC_10x8_UNORM_BLOCK, | ||
| 187 | VK_FORMAT_ASTC_10x8_SRGB_BLOCK, | ||
| 174 | VK_FORMAT_ASTC_10x10_UNORM_BLOCK, | 188 | VK_FORMAT_ASTC_10x10_UNORM_BLOCK, |
| 175 | VK_FORMAT_ASTC_10x10_SRGB_BLOCK, | 189 | VK_FORMAT_ASTC_10x10_SRGB_BLOCK, |
| 190 | VK_FORMAT_ASTC_12x10_UNORM_BLOCK, | ||
| 191 | VK_FORMAT_ASTC_12x10_SRGB_BLOCK, | ||
| 176 | VK_FORMAT_ASTC_12x12_UNORM_BLOCK, | 192 | VK_FORMAT_ASTC_12x12_UNORM_BLOCK, |
| 177 | VK_FORMAT_ASTC_12x12_SRGB_BLOCK, | 193 | VK_FORMAT_ASTC_12x12_SRGB_BLOCK, |
| 178 | VK_FORMAT_ASTC_8x6_UNORM_BLOCK, | 194 | VK_FORMAT_ASTC_8x6_UNORM_BLOCK, |
| @@ -192,7 +208,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( | |||
| 192 | 208 | ||
| 193 | VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, | 209 | VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, |
| 194 | VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) | 210 | VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) |
| 195 | : dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, | 211 | : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, |
| 196 | instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { | 212 | instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { |
| 197 | SetupFamilies(surface); | 213 | SetupFamilies(surface); |
| 198 | SetupFeatures(); | 214 | SetupFeatures(); |
| @@ -214,7 +230,7 @@ bool VKDevice::Create() { | |||
| 214 | features2.features = { | 230 | features2.features = { |
| 215 | .robustBufferAccess = false, | 231 | .robustBufferAccess = false, |
| 216 | .fullDrawIndexUint32 = false, | 232 | .fullDrawIndexUint32 = false, |
| 217 | .imageCubeArray = false, | 233 | .imageCubeArray = true, |
| 218 | .independentBlend = true, | 234 | .independentBlend = true, |
| 219 | .geometryShader = true, | 235 | .geometryShader = true, |
| 220 | .tessellationShader = true, | 236 | .tessellationShader = true, |
| @@ -242,7 +258,7 @@ bool VKDevice::Create() { | |||
| 242 | .shaderTessellationAndGeometryPointSize = false, | 258 | .shaderTessellationAndGeometryPointSize = false, |
| 243 | .shaderImageGatherExtended = true, | 259 | .shaderImageGatherExtended = true, |
| 244 | .shaderStorageImageExtendedFormats = false, | 260 | .shaderStorageImageExtendedFormats = false, |
| 245 | .shaderStorageImageMultisample = false, | 261 | .shaderStorageImageMultisample = true, |
| 246 | .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, | 262 | .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, |
| 247 | .shaderStorageImageWriteWithoutFormat = true, | 263 | .shaderStorageImageWriteWithoutFormat = true, |
| 248 | .shaderUniformBufferArrayDynamicIndexing = false, | 264 | .shaderUniformBufferArrayDynamicIndexing = false, |
| @@ -268,7 +284,6 @@ bool VKDevice::Create() { | |||
| 268 | .variableMultisampleRate = false, | 284 | .variableMultisampleRate = false, |
| 269 | .inheritedQueries = false, | 285 | .inheritedQueries = false, |
| 270 | }; | 286 | }; |
| 271 | |||
| 272 | VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{ | 287 | VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{ |
| 273 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR, | 288 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR, |
| 274 | .pNext = nullptr, | 289 | .pNext = nullptr, |
| @@ -380,6 +395,20 @@ bool VKDevice::Create() { | |||
| 380 | LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); | 395 | LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); |
| 381 | } | 396 | } |
| 382 | 397 | ||
| 398 | VkPhysicalDeviceRobustness2FeaturesEXT robustness2; | ||
| 399 | if (ext_robustness2) { | ||
| 400 | robustness2 = { | ||
| 401 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT, | ||
| 402 | .pNext = nullptr, | ||
| 403 | .robustBufferAccess2 = false, | ||
| 404 | .robustImageAccess2 = true, | ||
| 405 | .nullDescriptor = true, | ||
| 406 | }; | ||
| 407 | SetNext(next, robustness2); | ||
| 408 | } else { | ||
| 409 | LOG_INFO(Render_Vulkan, "Device doesn't support robustness2"); | ||
| 410 | } | ||
| 411 | |||
| 383 | if (!ext_depth_range_unrestricted) { | 412 | if (!ext_depth_range_unrestricted) { |
| 384 | LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); | 413 | LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); |
| 385 | } | 414 | } |
| @@ -405,7 +434,14 @@ bool VKDevice::Create() { | |||
| 405 | } | 434 | } |
| 406 | 435 | ||
| 407 | CollectTelemetryParameters(); | 436 | CollectTelemetryParameters(); |
| 437 | CollectToolingInfo(); | ||
| 408 | 438 | ||
| 439 | if (ext_extended_dynamic_state && driver_id == VK_DRIVER_ID_MESA_RADV) { | ||
| 440 | LOG_WARNING( | ||
| 441 | Render_Vulkan, | ||
| 442 | "Blacklisting RADV for VK_EXT_extended_dynamic state, likely due to a bug in yuzu"); | ||
| 443 | ext_extended_dynamic_state = false; | ||
| 444 | } | ||
| 409 | if (ext_extended_dynamic_state && IsRDNA(properties.deviceName, driver_id)) { | 445 | if (ext_extended_dynamic_state && IsRDNA(properties.deviceName, driver_id)) { |
| 410 | // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but on RDNA devices it | 446 | // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but on RDNA devices it |
| 411 | // seems to cause stability issues | 447 | // seems to cause stability issues |
| @@ -458,7 +494,7 @@ void VKDevice::ReportLoss() const { | |||
| 458 | LOG_CRITICAL(Render_Vulkan, "Device loss occured!"); | 494 | LOG_CRITICAL(Render_Vulkan, "Device loss occured!"); |
| 459 | 495 | ||
| 460 | // Wait for the log to flush and for Nsight Aftermath to dump the results | 496 | // Wait for the log to flush and for Nsight Aftermath to dump the results |
| 461 | std::this_thread::sleep_for(std::chrono::seconds{3}); | 497 | std::this_thread::sleep_for(std::chrono::seconds{15}); |
| 462 | } | 498 | } |
| 463 | 499 | ||
| 464 | void VKDevice::SaveShader(const std::vector<u32>& spirv) const { | 500 | void VKDevice::SaveShader(const std::vector<u32>& spirv) const { |
| @@ -499,6 +535,16 @@ bool VKDevice::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) | |||
| 499 | return true; | 535 | return true; |
| 500 | } | 536 | } |
| 501 | 537 | ||
| 538 | bool VKDevice::TestDepthStencilBlits() const { | ||
| 539 | static constexpr VkFormatFeatureFlags required_features = | ||
| 540 | VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; | ||
| 541 | const auto test_features = [](VkFormatProperties props) { | ||
| 542 | return (props.optimalTilingFeatures & required_features) == required_features; | ||
| 543 | }; | ||
| 544 | return test_features(format_properties.at(VK_FORMAT_D32_SFLOAT_S8_UINT)) && | ||
| 545 | test_features(format_properties.at(VK_FORMAT_D24_UNORM_S8_UINT)); | ||
| 546 | } | ||
| 547 | |||
| 502 | bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, | 548 | bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, |
| 503 | FormatType format_type) const { | 549 | FormatType format_type) const { |
| 504 | const auto it = format_properties.find(wanted_format); | 550 | const auto it = format_properties.find(wanted_format); |
| @@ -569,6 +615,7 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { | |||
| 569 | const auto features{physical.GetFeatures()}; | 615 | const auto features{physical.GetFeatures()}; |
| 570 | const std::array feature_report = { | 616 | const std::array feature_report = { |
| 571 | std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), | 617 | std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), |
| 618 | std::make_pair(features.imageCubeArray, "imageCubeArray"), | ||
| 572 | std::make_pair(features.independentBlend, "independentBlend"), | 619 | std::make_pair(features.independentBlend, "independentBlend"), |
| 573 | std::make_pair(features.depthClamp, "depthClamp"), | 620 | std::make_pair(features.depthClamp, "depthClamp"), |
| 574 | std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"), | 621 | std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"), |
| @@ -580,6 +627,7 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { | |||
| 580 | std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), | 627 | std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), |
| 581 | std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"), | 628 | std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"), |
| 582 | std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), | 629 | std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), |
| 630 | std::make_pair(features.shaderStorageImageMultisample, "shaderStorageImageMultisample"), | ||
| 583 | std::make_pair(features.shaderStorageImageWriteWithoutFormat, | 631 | std::make_pair(features.shaderStorageImageWriteWithoutFormat, |
| 584 | "shaderStorageImageWriteWithoutFormat"), | 632 | "shaderStorageImageWriteWithoutFormat"), |
| 585 | }; | 633 | }; |
| @@ -608,6 +656,7 @@ std::vector<const char*> VKDevice::LoadExtensions() { | |||
| 608 | bool has_ext_transform_feedback{}; | 656 | bool has_ext_transform_feedback{}; |
| 609 | bool has_ext_custom_border_color{}; | 657 | bool has_ext_custom_border_color{}; |
| 610 | bool has_ext_extended_dynamic_state{}; | 658 | bool has_ext_extended_dynamic_state{}; |
| 659 | bool has_ext_robustness2{}; | ||
| 611 | for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) { | 660 | for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) { |
| 612 | const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name, | 661 | const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name, |
| 613 | bool push) { | 662 | bool push) { |
| @@ -627,11 +676,15 @@ std::vector<const char*> VKDevice::LoadExtensions() { | |||
| 627 | test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); | 676 | test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); |
| 628 | test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); | 677 | test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); |
| 629 | test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); | 678 | test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); |
| 679 | test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true); | ||
| 630 | test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, | 680 | test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, |
| 631 | true); | 681 | true); |
| 682 | test(ext_tooling_info, VK_EXT_TOOLING_INFO_EXTENSION_NAME, true); | ||
| 683 | test(ext_shader_stencil_export, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, true); | ||
| 632 | test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false); | 684 | test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false); |
| 633 | test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); | 685 | test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); |
| 634 | test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); | 686 | test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); |
| 687 | test(has_ext_robustness2, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, false); | ||
| 635 | if (instance_version >= VK_API_VERSION_1_1) { | 688 | if (instance_version >= VK_API_VERSION_1_1) { |
| 636 | test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); | 689 | test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); |
| 637 | } | 690 | } |
| @@ -733,6 +786,18 @@ std::vector<const char*> VKDevice::LoadExtensions() { | |||
| 733 | } | 786 | } |
| 734 | } | 787 | } |
| 735 | 788 | ||
| 789 | if (has_ext_robustness2) { | ||
| 790 | VkPhysicalDeviceRobustness2FeaturesEXT robustness2; | ||
| 791 | robustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; | ||
| 792 | robustness2.pNext = nullptr; | ||
| 793 | features.pNext = &robustness2; | ||
| 794 | physical.GetFeatures2KHR(features); | ||
| 795 | if (robustness2.nullDescriptor && robustness2.robustImageAccess2) { | ||
| 796 | extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); | ||
| 797 | ext_robustness2 = true; | ||
| 798 | } | ||
| 799 | } | ||
| 800 | |||
| 736 | return extensions; | 801 | return extensions; |
| 737 | } | 802 | } |
| 738 | 803 | ||
| @@ -764,6 +829,7 @@ void VKDevice::SetupFamilies(VkSurfaceKHR surface) { | |||
| 764 | void VKDevice::SetupFeatures() { | 829 | void VKDevice::SetupFeatures() { |
| 765 | const auto supported_features{physical.GetFeatures()}; | 830 | const auto supported_features{physical.GetFeatures()}; |
| 766 | is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; | 831 | is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; |
| 832 | is_blit_depth_stencil_supported = TestDepthStencilBlits(); | ||
| 767 | is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); | 833 | is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); |
| 768 | } | 834 | } |
| 769 | 835 | ||
| @@ -794,6 +860,32 @@ void VKDevice::CollectTelemetryParameters() { | |||
| 794 | } | 860 | } |
| 795 | } | 861 | } |
| 796 | 862 | ||
| 863 | void VKDevice::CollectToolingInfo() { | ||
| 864 | if (!ext_tooling_info) { | ||
| 865 | return; | ||
| 866 | } | ||
| 867 | const auto vkGetPhysicalDeviceToolPropertiesEXT = | ||
| 868 | reinterpret_cast<PFN_vkGetPhysicalDeviceToolPropertiesEXT>( | ||
| 869 | dld.vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceToolPropertiesEXT")); | ||
| 870 | if (!vkGetPhysicalDeviceToolPropertiesEXT) { | ||
| 871 | return; | ||
| 872 | } | ||
| 873 | u32 tool_count = 0; | ||
| 874 | if (vkGetPhysicalDeviceToolPropertiesEXT(physical, &tool_count, nullptr) != VK_SUCCESS) { | ||
| 875 | return; | ||
| 876 | } | ||
| 877 | std::vector<VkPhysicalDeviceToolPropertiesEXT> tools(tool_count); | ||
| 878 | if (vkGetPhysicalDeviceToolPropertiesEXT(physical, &tool_count, tools.data()) != VK_SUCCESS) { | ||
| 879 | return; | ||
| 880 | } | ||
| 881 | for (const VkPhysicalDeviceToolPropertiesEXT& tool : tools) { | ||
| 882 | const std::string_view name = tool.name; | ||
| 883 | LOG_INFO(Render_Vulkan, "{}", name); | ||
| 884 | has_renderdoc = has_renderdoc || name == "RenderDoc"; | ||
| 885 | has_nsight_graphics = has_nsight_graphics || name == "NVIDIA Nsight Graphics"; | ||
| 886 | } | ||
| 887 | } | ||
| 888 | |||
| 797 | std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { | 889 | std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { |
| 798 | static constexpr float QUEUE_PRIORITY = 1.0f; | 890 | static constexpr float QUEUE_PRIORITY = 1.0f; |
| 799 | 891 | ||
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index 4286673d9..995dcfc0f 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h | |||
| @@ -157,6 +157,11 @@ public: | |||
| 157 | return is_formatless_image_load_supported; | 157 | return is_formatless_image_load_supported; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | /// Returns true when blitting from and to depth stencil images is supported. | ||
| 161 | bool IsBlitDepthStencilSupported() const { | ||
| 162 | return is_blit_depth_stencil_supported; | ||
| 163 | } | ||
| 164 | |||
| 160 | /// Returns true if the device supports VK_NV_viewport_swizzle. | 165 | /// Returns true if the device supports VK_NV_viewport_swizzle. |
| 161 | bool IsNvViewportSwizzleSupported() const { | 166 | bool IsNvViewportSwizzleSupported() const { |
| 162 | return nv_viewport_swizzle; | 167 | return nv_viewport_swizzle; |
| @@ -172,6 +177,11 @@ public: | |||
| 172 | return ext_index_type_uint8; | 177 | return ext_index_type_uint8; |
| 173 | } | 178 | } |
| 174 | 179 | ||
| 180 | /// Returns true if the device supports VK_EXT_sampler_filter_minmax. | ||
| 181 | bool IsExtSamplerFilterMinmaxSupported() const { | ||
| 182 | return ext_sampler_filter_minmax; | ||
| 183 | } | ||
| 184 | |||
| 175 | /// Returns true if the device supports VK_EXT_depth_range_unrestricted. | 185 | /// Returns true if the device supports VK_EXT_depth_range_unrestricted. |
| 176 | bool IsExtDepthRangeUnrestrictedSupported() const { | 186 | bool IsExtDepthRangeUnrestrictedSupported() const { |
| 177 | return ext_depth_range_unrestricted; | 187 | return ext_depth_range_unrestricted; |
| @@ -197,6 +207,16 @@ public: | |||
| 197 | return ext_extended_dynamic_state; | 207 | return ext_extended_dynamic_state; |
| 198 | } | 208 | } |
| 199 | 209 | ||
| 210 | /// Returns true if the device supports VK_EXT_shader_stencil_export. | ||
| 211 | bool IsExtShaderStencilExportSupported() const { | ||
| 212 | return ext_shader_stencil_export; | ||
| 213 | } | ||
| 214 | |||
| 215 | /// Returns true when a known debugging tool is attached. | ||
| 216 | bool HasDebuggingToolAttached() const { | ||
| 217 | return has_renderdoc || has_nsight_graphics; | ||
| 218 | } | ||
| 219 | |||
| 200 | /// Returns the vendor name reported from Vulkan. | 220 | /// Returns the vendor name reported from Vulkan. |
| 201 | std::string_view GetVendorName() const { | 221 | std::string_view GetVendorName() const { |
| 202 | return vendor_name; | 222 | return vendor_name; |
| @@ -228,16 +248,23 @@ private: | |||
| 228 | /// Collects telemetry information from the device. | 248 | /// Collects telemetry information from the device. |
| 229 | void CollectTelemetryParameters(); | 249 | void CollectTelemetryParameters(); |
| 230 | 250 | ||
| 251 | /// Collects information about attached tools. | ||
| 252 | void CollectToolingInfo(); | ||
| 253 | |||
| 231 | /// Returns a list of queue initialization descriptors. | 254 | /// Returns a list of queue initialization descriptors. |
| 232 | std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const; | 255 | std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const; |
| 233 | 256 | ||
| 234 | /// Returns true if ASTC textures are natively supported. | 257 | /// Returns true if ASTC textures are natively supported. |
| 235 | bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const; | 258 | bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const; |
| 236 | 259 | ||
| 260 | /// Returns true if the device natively supports blitting depth stencil images. | ||
| 261 | bool TestDepthStencilBlits() const; | ||
| 262 | |||
| 237 | /// Returns true if a format is supported. | 263 | /// Returns true if a format is supported. |
| 238 | bool IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, | 264 | bool IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, |
| 239 | FormatType format_type) const; | 265 | FormatType format_type) const; |
| 240 | 266 | ||
| 267 | VkInstance instance; ///< Vulkan instance. | ||
| 241 | vk::DeviceDispatch dld; ///< Device function pointers. | 268 | vk::DeviceDispatch dld; ///< Device function pointers. |
| 242 | vk::PhysicalDevice physical; ///< Physical device. | 269 | vk::PhysicalDevice physical; ///< Physical device. |
| 243 | VkPhysicalDeviceProperties properties; ///< Device properties. | 270 | VkPhysicalDeviceProperties properties; ///< Device properties. |
| @@ -253,15 +280,22 @@ private: | |||
| 253 | bool is_float16_supported{}; ///< Support for float16 arithmetics. | 280 | bool is_float16_supported{}; ///< Support for float16 arithmetics. |
| 254 | bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. | 281 | bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. |
| 255 | bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. | 282 | bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. |
| 283 | bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil. | ||
| 256 | bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. | 284 | bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. |
| 257 | bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs. | 285 | bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs. |
| 258 | bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. | 286 | bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. |
| 287 | bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. | ||
| 259 | bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. | 288 | bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. |
| 260 | bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. | 289 | bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. |
| 290 | bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info. | ||
| 261 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. | 291 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. |
| 262 | bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. | 292 | bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. |
| 263 | bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. | 293 | bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. |
| 294 | bool ext_robustness2{}; ///< Support for VK_EXT_robustness2. | ||
| 295 | bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. | ||
| 264 | bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. | 296 | bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. |
| 297 | bool has_renderdoc{}; ///< Has RenderDoc attached | ||
| 298 | bool has_nsight_graphics{}; ///< Has Nsight Graphics attached | ||
| 265 | 299 | ||
| 266 | // Asynchronous Graphics Pipeline setting | 300 | // Asynchronous Graphics Pipeline setting |
| 267 | bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline | 301 | bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline |
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp index 0bcaee714..774a12a53 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp | |||
| @@ -73,10 +73,9 @@ bool InnerFence::IsEventSignalled() const { | |||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, | 75 | VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, |
| 76 | Tegra::MemoryManager& memory_manager_, | 76 | Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, |
| 77 | VKTextureCache& texture_cache_, VKBufferCache& buffer_cache_, | 77 | VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, |
| 78 | VKQueryCache& query_cache_, const VKDevice& device_, | 78 | const VKDevice& device_, VKScheduler& scheduler_) |
| 79 | VKScheduler& scheduler_) | ||
| 80 | : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, | 79 | : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, |
| 81 | device{device_}, scheduler{scheduler_} {} | 80 | device{device_}, scheduler{scheduler_} {} |
| 82 | 81 | ||
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h index c8547cc24..c2869e8e3 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.h +++ b/src/video_core/renderer_vulkan/vk_fence_manager.h | |||
| @@ -8,6 +8,7 @@ | |||
| 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/vk_texture_cache.h" | ||
| 11 | #include "video_core/renderer_vulkan/wrapper.h" | 12 | #include "video_core/renderer_vulkan/wrapper.h" |
| 12 | 13 | ||
| 13 | namespace Core { | 14 | namespace Core { |
| @@ -24,7 +25,6 @@ class VKBufferCache; | |||
| 24 | class VKDevice; | 25 | 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: |
| @@ -51,12 +51,12 @@ 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 VKDevice& device_, VKScheduler& scheduler_); |
| 62 | 62 | ||
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 970979fa1..7979df3a8 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #include "video_core/renderer_vulkan/vk_device.h" | 15 | #include "video_core/renderer_vulkan/vk_device.h" |
| 16 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 16 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 17 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 17 | #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" | 18 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 20 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 19 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 21 | #include "video_core/renderer_vulkan/wrapper.h" | 20 | #include "video_core/renderer_vulkan/wrapper.h" |
| @@ -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 VKDevice& 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_, | 100 | const GraphicsPipelineCacheKey& key, |
| 78 | const GraphicsPipelineCacheKey& key_, | 101 | vk::Span<VkDescriptorSetLayoutBinding> bindings, |
| 79 | vk::Span<VkDescriptorSetLayoutBinding> bindings_, | 102 | const SPIRVProgram& program, u32 num_color_buffers) |
| 80 | const SPIRVProgram& program_) | 103 | : device{device_}, scheduler{scheduler_}, cache_key{key}, hash{cache_key.Hash()}, |
| 81 | : device{device_}, scheduler{scheduler_}, cache_key{key_}, hash{cache_key.Hash()}, | 104 | descriptor_set_layout{CreateDescriptorSetLayout(bindings)}, |
| 82 | 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 | ||
| @@ -179,8 +200,9 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( | |||
| 179 | return shader_modules; | 200 | return shader_modules; |
| 180 | } | 201 | } |
| 181 | 202 | ||
| 182 | vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, | 203 | vk::Pipeline VKGraphicsPipeline::CreatePipeline(const SPIRVProgram& program, |
| 183 | const SPIRVProgram& program) const { | 204 | VkRenderPass renderpass, |
| 205 | u32 num_color_buffers) const { | ||
| 184 | const auto& state = cache_key.fixed_state; | 206 | const auto& state = cache_key.fixed_state; |
| 185 | const auto& viewport_swizzles = state.viewport_swizzles; | 207 | const auto& viewport_swizzles = state.viewport_swizzles; |
| 186 | 208 | ||
| @@ -290,8 +312,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 290 | }; | 312 | }; |
| 291 | 313 | ||
| 292 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; | 314 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; |
| 293 | std::transform(viewport_swizzles.begin(), viewport_swizzles.end(), swizzles.begin(), | 315 | std::ranges::transform(viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); |
| 294 | UnpackViewportSwizzle); | ||
| 295 | VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ | 316 | VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ |
| 296 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, | 317 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, |
| 297 | .pNext = nullptr, | 318 | .pNext = nullptr, |
| @@ -326,7 +347,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 326 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | 347 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| 327 | .pNext = nullptr, | 348 | .pNext = nullptr, |
| 328 | .flags = 0, | 349 | .flags = 0, |
| 329 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | 350 | .rasterizationSamples = ConvertMsaaMode(state.msaa_mode), |
| 330 | .sampleShadingEnable = VK_FALSE, | 351 | .sampleShadingEnable = VK_FALSE, |
| 331 | .minSampleShading = 0.0f, | 352 | .minSampleShading = 0.0f, |
| 332 | .pSampleMask = nullptr, | 353 | .pSampleMask = nullptr, |
| @@ -352,8 +373,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 352 | }; | 373 | }; |
| 353 | 374 | ||
| 354 | std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; | 375 | std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; |
| 355 | const auto num_attachments = static_cast<std::size_t>(renderpass_params.num_color_attachments); | 376 | for (std::size_t index = 0; index < num_color_buffers; ++index) { |
| 356 | for (std::size_t index = 0; index < num_attachments; ++index) { | ||
| 357 | static constexpr std::array COMPONENT_TABLE{ | 377 | static constexpr std::array COMPONENT_TABLE{ |
| 358 | VK_COLOR_COMPONENT_R_BIT, | 378 | VK_COLOR_COMPONENT_R_BIT, |
| 359 | VK_COLOR_COMPONENT_G_BIT, | 379 | VK_COLOR_COMPONENT_G_BIT, |
| @@ -387,7 +407,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 387 | .flags = 0, | 407 | .flags = 0, |
| 388 | .logicOpEnable = VK_FALSE, | 408 | .logicOpEnable = VK_FALSE, |
| 389 | .logicOp = VK_LOGIC_OP_COPY, | 409 | .logicOp = VK_LOGIC_OP_COPY, |
| 390 | .attachmentCount = static_cast<u32>(num_attachments), | 410 | .attachmentCount = num_color_buffers, |
| 391 | .pAttachments = cb_attachments.data(), | 411 | .pAttachments = cb_attachments.data(), |
| 392 | .blendConstants = {}, | 412 | .blendConstants = {}, |
| 393 | }; | 413 | }; |
| @@ -447,8 +467,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 447 | stage_ci.pNext = &subgroup_size_ci; | 467 | stage_ci.pNext = &subgroup_size_ci; |
| 448 | } | 468 | } |
| 449 | } | 469 | } |
| 450 | 470 | return device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ | |
| 451 | const VkGraphicsPipelineCreateInfo ci{ | ||
| 452 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | 471 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, |
| 453 | .pNext = nullptr, | 472 | .pNext = nullptr, |
| 454 | .flags = 0, | 473 | .flags = 0, |
| @@ -468,8 +487,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 468 | .subpass = 0, | 487 | .subpass = 0, |
| 469 | .basePipelineHandle = nullptr, | 488 | .basePipelineHandle = nullptr, |
| 470 | .basePipelineIndex = 0, | 489 | .basePipelineIndex = 0, |
| 471 | }; | 490 | }); |
| 472 | return device.GetLogical().CreateGraphicsPipeline(ci); | ||
| 473 | } | 491 | } |
| 474 | 492 | ||
| 475 | } // namespace Vulkan | 493 | } // 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 3fb31d55a..214d06b4c 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h | |||
| @@ -8,10 +8,10 @@ | |||
| 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/renderer_vulkan/wrapper.h" |
| 17 | 17 | ||
| @@ -20,8 +20,7 @@ namespace Vulkan { | |||
| 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,7 +33,7 @@ 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>); |
| @@ -43,7 +42,6 @@ static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>); | |||
| 43 | 42 | ||
| 44 | class VKDescriptorPool; | 43 | class VKDescriptorPool; |
| 45 | class VKDevice; | 44 | class VKDevice; |
| 46 | class VKRenderPassCache; | ||
| 47 | class VKScheduler; | 45 | class VKScheduler; |
| 48 | class VKUpdateDescriptorQueue; | 46 | class VKUpdateDescriptorQueue; |
| 49 | 47 | ||
| @@ -52,12 +50,11 @@ using SPIRVProgram = std::array<std::optional<SPIRVShader>, Maxwell::MaxShaderSt | |||
| 52 | class VKGraphicsPipeline final { | 50 | class VKGraphicsPipeline final { |
| 53 | public: | 51 | public: |
| 54 | explicit VKGraphicsPipeline(const VKDevice& device_, VKScheduler& scheduler_, | 52 | explicit VKGraphicsPipeline(const VKDevice& 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_, | 55 | const GraphicsPipelineCacheKey& key, |
| 58 | const GraphicsPipelineCacheKey& key_, | 56 | vk::Span<VkDescriptorSetLayoutBinding> bindings, |
| 59 | vk::Span<VkDescriptorSetLayoutBinding> bindings_, | 57 | const SPIRVProgram& program, u32 num_color_buffers); |
| 60 | const SPIRVProgram& program_); | ||
| 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,8 +82,8 @@ 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 VKDevice& device; |
| 96 | VKScheduler& scheduler; | 89 | VKScheduler& scheduler; |
| @@ -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 072d14e3b..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_, | ||
| 17 | const VkImageCreateInfo& image_ci_, 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 287ab90ca..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_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp index be53d450f..56b24b70f 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp | |||
| @@ -216,7 +216,7 @@ VKMemoryCommitImpl::~VKMemoryCommitImpl() { | |||
| 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 39f903ec8..318f8b43e 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ b/src/video_core/renderer_vulkan/vk_memory_manager.h | |||
| @@ -5,6 +5,7 @@ | |||
| 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" |
| @@ -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 3fb264d03..083796d05 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "common/bit_cast.h" | 10 | #include "common/bit_cast.h" |
| 11 | #include "common/cityhash.h" | ||
| 11 | #include "common/microprofile.h" | 12 | #include "common/microprofile.h" |
| 12 | #include "core/core.h" | 13 | #include "core/core.h" |
| 13 | #include "core/memory.h" | 14 | #include "core/memory.h" |
| @@ -22,7 +23,6 @@ | |||
| 22 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 23 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 23 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 24 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 24 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 25 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 25 | #include "video_core/renderer_vulkan/vk_renderpass_cache.h" | ||
| 26 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 26 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 27 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 27 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 28 | #include "video_core/renderer_vulkan/wrapper.h" | 28 | #include "video_core/renderer_vulkan/wrapper.h" |
| @@ -52,7 +52,9 @@ constexpr VkDescriptorType STORAGE_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_TEX | |||
| 52 | constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; | 52 | constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; |
| 53 | 53 | ||
| 54 | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ | 54 | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ |
| 55 | VideoCommon::Shader::CompileDepth::FullDecompile}; | 55 | .depth = VideoCommon::Shader::CompileDepth::FullDecompile, |
| 56 | .disable_else_derivation = true, | ||
| 57 | }; | ||
| 56 | 58 | ||
| 57 | constexpr std::size_t GetStageFromProgram(std::size_t program) { | 59 | constexpr std::size_t GetStageFromProgram(std::size_t program) { |
| 58 | return program == 0 ? 0 : program - 1; | 60 | return program == 0 ? 0 : program - 1; |
| @@ -149,12 +151,11 @@ VKPipelineCache::VKPipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_ | |||
| 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 VKDevice& 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 | : ShaderCache{rasterizer_}, gpu{gpu_}, maxwell3d{maxwell3d_}, kepler_compute{kepler_compute_}, | 156 | kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_}, |
| 155 | gpu_memory{gpu_memory_}, device{device_}, scheduler{scheduler_}, | 157 | scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, update_descriptor_queue{ |
| 156 | descriptor_pool{descriptor_pool_}, update_descriptor_queue{update_descriptor_queue_}, | 158 | update_descriptor_queue_} {} |
| 157 | renderpass_cache{renderpass_cache_} {} | ||
| 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(); |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 9e1f8fcbb..fbaa8257c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -19,7 +19,6 @@ | |||
| 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" | 23 | #include "video_core/renderer_vulkan/wrapper.h" |
| 25 | #include "video_core/shader/async_shaders.h" | 24 | #include "video_core/shader/async_shaders.h" |
| @@ -119,18 +118,18 @@ private: | |||
| 119 | 118 | ||
| 120 | class VKPipelineCache final : public VideoCommon::ShaderCache<Shader> { | 119 | class VKPipelineCache final : public VideoCommon::ShaderCache<Shader> { |
| 121 | public: | 120 | 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 VKDevice& 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); |
| @@ -153,7 +152,6 @@ private: | |||
| 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_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f93986aab..04c5c859c 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" |
| @@ -30,8 +31,6 @@ | |||
| 30 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" | 31 | #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" |
| 31 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 32 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 32 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 33 | #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" | 34 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 36 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 35 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 37 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 36 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| @@ -39,10 +38,13 @@ | |||
| 39 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 38 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 40 | #include "video_core/renderer_vulkan/wrapper.h" | 39 | #include "video_core/renderer_vulkan/wrapper.h" |
| 41 | #include "video_core/shader_cache.h" | 40 | #include "video_core/shader_cache.h" |
| 41 | #include "video_core/texture_cache/texture_cache.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 VKDevice& 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(Tegra::Texture::TextureHandle{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(Tegra::Texture::TextureHandle{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 { |
| @@ -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,7 +329,7 @@ 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 VKDevice& device, VKScheduler& scheduler) const { |
| 308 | if (device.IsExtExtendedDynamicStateSupported()) { | 334 | if (device.IsExtExtendedDynamicStateSupported()) { |
| 309 | if (index.buffer) { | 335 | if (index.buffer) { |
| @@ -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) { |
| @@ -385,20 +411,23 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra | |||
| 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 VKDevice& 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_) { |
| @@ -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(); |
| 522 | const VkExtent2D render_area = framebuffer->RenderArea(); | ||
| 523 | scheduler.RequestRenderpass(framebuffer); | ||
| 501 | 524 | ||
| 502 | const VkRenderPass renderpass = renderpass_cache.GetRenderPass(GetRenderPassParams(0)); | 525 | VkClearRect clear_rect{ |
| 503 | const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass); | 526 | .rect = GetScissorState(regs, 0), |
| 504 | scheduler.RequestRenderpass(renderpass, framebuffer, render_area); | 527 | .baseArrayLayer = regs.clear_buffers.layer, |
| 505 | 528 | .layerCount = 1, | |
| 506 | VkClearRect clear_rect; | 529 | }; |
| 507 | clear_rect.baseArrayLayer = regs.clear_buffers.layer; | 530 | if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) { |
| 508 | clear_rect.layerCount = 1; | 531 | return; |
| 509 | clear_rect.rect = GetScissorState(regs, 0); | 532 | } |
| 510 | clear_rect.rect.extent.width = std::min(clear_rect.rect.extent.width, render_area.width); | 533 | clear_rect.rect.extent = VkExtent2D{ |
| 511 | clear_rect.rect.extent.height = std::min(clear_rect.rect.extent.height, render_area.height); | 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,29 +592,43 @@ 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); | ||
| 584 | 609 | ||
| 585 | TransitionImages(sampled_views, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 610 | buffer_cache.Map(CalculateComputeStreamBufferSize()); |
| 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 | 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); | ||
| 621 | |||
| 622 | buffer_cache.Unmap(); | ||
| 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 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, DESCRIPTOR_SET, |
| 596 | descriptor_set, {}); | 632 | descriptor_set, {}); |
| 597 | cmdbuf.Dispatch(grid_x, grid_y, grid_z); | 633 | cmdbuf.Dispatch(grid_x, grid_y, grid_z); |
| 598 | }); | 634 | }); |
| @@ -613,7 +649,10 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) { | |||
| 613 | if (addr == 0 || size == 0) { | 649 | if (addr == 0 || size == 0) { |
| 614 | return; | 650 | return; |
| 615 | } | 651 | } |
| 616 | texture_cache.FlushRegion(addr, size); | 652 | { |
| 653 | auto lock = texture_cache.AcquireLock(); | ||
| 654 | texture_cache.DownloadMemory(addr, size); | ||
| 655 | } | ||
| 617 | buffer_cache.FlushRegion(addr, size); | 656 | buffer_cache.FlushRegion(addr, size); |
| 618 | query_cache.FlushRegion(addr, size); | 657 | query_cache.FlushRegion(addr, size); |
| 619 | } | 658 | } |
| @@ -622,14 +661,18 @@ bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) { | |||
| 622 | if (!Settings::IsGPULevelHigh()) { | 661 | if (!Settings::IsGPULevelHigh()) { |
| 623 | return buffer_cache.MustFlushRegion(addr, size); | 662 | return buffer_cache.MustFlushRegion(addr, size); |
| 624 | } | 663 | } |
| 625 | return texture_cache.MustFlushRegion(addr, size) || buffer_cache.MustFlushRegion(addr, size); | 664 | return texture_cache.IsRegionGpuModified(addr, size) || |
| 665 | buffer_cache.MustFlushRegion(addr, size); | ||
| 626 | } | 666 | } |
| 627 | 667 | ||
| 628 | void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) { | 668 | void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) { |
| 629 | if (addr == 0 || size == 0) { | 669 | if (addr == 0 || size == 0) { |
| 630 | return; | 670 | return; |
| 631 | } | 671 | } |
| 632 | texture_cache.InvalidateRegion(addr, size); | 672 | { |
| 673 | auto lock = texture_cache.AcquireLock(); | ||
| 674 | texture_cache.WriteMemory(addr, size); | ||
| 675 | } | ||
| 633 | pipeline_cache.InvalidateRegion(addr, size); | 676 | pipeline_cache.InvalidateRegion(addr, size); |
| 634 | buffer_cache.InvalidateRegion(addr, size); | 677 | buffer_cache.InvalidateRegion(addr, size); |
| 635 | query_cache.InvalidateRegion(addr, size); | 678 | query_cache.InvalidateRegion(addr, size); |
| @@ -639,17 +682,28 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) { | |||
| 639 | if (addr == 0 || size == 0) { | 682 | if (addr == 0 || size == 0) { |
| 640 | return; | 683 | return; |
| 641 | } | 684 | } |
| 642 | texture_cache.OnCPUWrite(addr, size); | 685 | { |
| 686 | auto lock = texture_cache.AcquireLock(); | ||
| 687 | texture_cache.WriteMemory(addr, size); | ||
| 688 | } | ||
| 643 | pipeline_cache.OnCPUWrite(addr, size); | 689 | pipeline_cache.OnCPUWrite(addr, size); |
| 644 | buffer_cache.OnCPUWrite(addr, size); | 690 | buffer_cache.OnCPUWrite(addr, size); |
| 645 | } | 691 | } |
| 646 | 692 | ||
| 647 | void RasterizerVulkan::SyncGuestHost() { | 693 | void RasterizerVulkan::SyncGuestHost() { |
| 648 | texture_cache.SyncGuestHost(); | ||
| 649 | buffer_cache.SyncGuestHost(); | 694 | buffer_cache.SyncGuestHost(); |
| 650 | pipeline_cache.SyncGuestHost(); | 695 | pipeline_cache.SyncGuestHost(); |
| 651 | } | 696 | } |
| 652 | 697 | ||
| 698 | void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) { | ||
| 699 | { | ||
| 700 | auto lock = texture_cache.AcquireLock(); | ||
| 701 | texture_cache.UnmapMemory(addr, size); | ||
| 702 | } | ||
| 703 | buffer_cache.OnCPUWrite(addr, size); | ||
| 704 | pipeline_cache.OnCPUWrite(addr, size); | ||
| 705 | } | ||
| 706 | |||
| 653 | void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { | 707 | void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { |
| 654 | if (!gpu.IsAsync()) { | 708 | if (!gpu.IsAsync()) { |
| 655 | gpu_memory.Write<u32>(addr, value); | 709 | gpu_memory.Write<u32>(addr, value); |
| @@ -700,6 +754,14 @@ void RasterizerVulkan::WaitForIdle() { | |||
| 700 | }); | 754 | }); |
| 701 | } | 755 | } |
| 702 | 756 | ||
| 757 | void RasterizerVulkan::FragmentBarrier() { | ||
| 758 | // We already put barriers when a render pass finishes | ||
| 759 | } | ||
| 760 | |||
| 761 | void RasterizerVulkan::TiledCacheBarrier() { | ||
| 762 | // TODO: Implementing tiled barriers requires rewriting a good chunk of the Vulkan backend | ||
| 763 | } | ||
| 764 | |||
| 703 | void RasterizerVulkan::FlushCommands() { | 765 | void RasterizerVulkan::FlushCommands() { |
| 704 | if (draw_counter > 0) { | 766 | if (draw_counter > 0) { |
| 705 | draw_counter = 0; | 767 | draw_counter = 0; |
| @@ -710,14 +772,20 @@ void RasterizerVulkan::FlushCommands() { | |||
| 710 | void RasterizerVulkan::TickFrame() { | 772 | void RasterizerVulkan::TickFrame() { |
| 711 | draw_counter = 0; | 773 | draw_counter = 0; |
| 712 | update_descriptor_queue.TickFrame(); | 774 | update_descriptor_queue.TickFrame(); |
| 775 | fence_manager.TickFrame(); | ||
| 713 | buffer_cache.TickFrame(); | 776 | buffer_cache.TickFrame(); |
| 714 | staging_pool.TickFrame(); | 777 | staging_pool.TickFrame(); |
| 778 | { | ||
| 779 | auto lock = texture_cache.AcquireLock(); | ||
| 780 | texture_cache.TickFrame(); | ||
| 781 | } | ||
| 715 | } | 782 | } |
| 716 | 783 | ||
| 717 | bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, | 784 | bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, |
| 718 | const Tegra::Engines::Fermi2D::Regs::Surface& dst, | 785 | const Tegra::Engines::Fermi2D::Surface& dst, |
| 719 | const Tegra::Engines::Fermi2D::Config& copy_config) { | 786 | const Tegra::Engines::Fermi2D::Config& copy_config) { |
| 720 | texture_cache.DoFermiCopy(src, dst, copy_config); | 787 | auto lock = texture_cache.AcquireLock(); |
| 788 | texture_cache.BlitImage(dst, src, copy_config); | ||
| 721 | return true; | 789 | return true; |
| 722 | } | 790 | } |
| 723 | 791 | ||
| @@ -727,20 +795,16 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 727 | return false; | 795 | return false; |
| 728 | } | 796 | } |
| 729 | 797 | ||
| 730 | const auto surface{texture_cache.TryFindFramebufferSurface(framebuffer_addr)}; | 798 | auto lock = texture_cache.AcquireLock(); |
| 731 | if (!surface) { | 799 | ImageView* const image_view = texture_cache.TryFindFramebufferImageView(framebuffer_addr); |
| 800 | if (!image_view) { | ||
| 732 | return false; | 801 | return false; |
| 733 | } | 802 | } |
| 734 | 803 | ||
| 735 | // Verify that the cached surface is the same size and format as the requested framebuffer | 804 | screen_info.image_view = image_view->Handle(VideoCommon::ImageViewType::e2D); |
| 736 | const auto& params{surface->GetSurfaceParams()}; | 805 | screen_info.width = image_view->size.width; |
| 737 | ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); | 806 | screen_info.height = image_view->size.height; |
| 738 | ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); | 807 | 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; | 808 | return true; |
| 745 | } | 809 | } |
| 746 | 810 | ||
| @@ -765,103 +829,6 @@ void RasterizerVulkan::FlushWork() { | |||
| 765 | draw_counter = 0; | 829 | draw_counter = 0; |
| 766 | } | 830 | } |
| 767 | 831 | ||
| 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, | 832 | RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineState& fixed_state, |
| 866 | BufferBindings& buffer_bindings, | 833 | BufferBindings& buffer_bindings, |
| 867 | bool is_indexed, | 834 | bool is_indexed, |
| @@ -885,50 +852,37 @@ RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineSt | |||
| 885 | 852 | ||
| 886 | void RasterizerVulkan::SetupShaderDescriptors( | 853 | void RasterizerVulkan::SetupShaderDescriptors( |
| 887 | const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { | 854 | const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { |
| 888 | texture_cache.GuardSamplers(true); | 855 | image_view_indices.clear(); |
| 889 | 856 | sampler_handles.clear(); | |
| 890 | for (std::size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { | 857 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { |
| 891 | // Skip VertexA stage | ||
| 892 | Shader* const shader = shaders[stage + 1]; | 858 | Shader* const shader = shaders[stage + 1]; |
| 893 | if (!shader) { | 859 | if (!shader) { |
| 894 | continue; | 860 | continue; |
| 895 | } | 861 | } |
| 896 | const auto& entries = shader->GetEntries(); | 862 | const auto& entries = shader->GetEntries(); |
| 897 | SetupGraphicsConstBuffers(entries, stage); | ||
| 898 | SetupGraphicsGlobalBuffers(entries, stage); | ||
| 899 | SetupGraphicsUniformTexels(entries, stage); | 863 | SetupGraphicsUniformTexels(entries, stage); |
| 900 | SetupGraphicsTextures(entries, stage); | 864 | SetupGraphicsTextures(entries, stage); |
| 901 | SetupGraphicsStorageTexels(entries, stage); | 865 | SetupGraphicsStorageTexels(entries, stage); |
| 902 | SetupGraphicsImages(entries, stage); | 866 | SetupGraphicsImages(entries, stage); |
| 903 | } | 867 | } |
| 904 | texture_cache.GuardSamplers(false); | 868 | const std::span indices_span(image_view_indices.data(), image_view_indices.size()); |
| 905 | } | 869 | texture_cache.FillGraphicsImageViews(indices_span, image_view_ids); |
| 906 | 870 | ||
| 907 | void RasterizerVulkan::SetupImageTransitions(Texceptions texceptions, const ColorAttachments& color, | 871 | update_descriptor_queue.Acquire(); |
| 908 | const ZetaAttachment& zeta) { | ||
| 909 | TransitionImages(sampled_views, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT); | ||
| 910 | TransitionImages(image_views, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, | ||
| 911 | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); | ||
| 912 | 872 | ||
| 913 | for (std::size_t rt = 0; rt < color.size(); ++rt) { | 873 | ImageViewId* image_view_id_ptr = image_view_ids.data(); |
| 914 | const auto color_attachment = color[rt]; | 874 | VkSampler* sampler_ptr = sampler_handles.data(); |
| 915 | if (color_attachment == nullptr) { | 875 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { |
| 876 | // Skip VertexA stage | ||
| 877 | Shader* const shader = shaders[stage + 1]; | ||
| 878 | if (!shader) { | ||
| 916 | continue; | 879 | continue; |
| 917 | } | 880 | } |
| 918 | const auto image_layout = | 881 | const auto& entries = shader->GetEntries(); |
| 919 | texceptions[rt] ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | 882 | SetupGraphicsConstBuffers(entries, stage); |
| 920 | color_attachment->Transition(image_layout, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | 883 | SetupGraphicsGlobalBuffers(entries, stage); |
| 921 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | | 884 | PushImageDescriptors(entries, texture_cache, update_descriptor_queue, image_view_id_ptr, |
| 922 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); | 885 | sampler_ptr); |
| 923 | } | ||
| 924 | |||
| 925 | if (zeta != nullptr) { | ||
| 926 | const auto image_layout = texceptions[ZETA_TEXCEPTION_INDEX] | ||
| 927 | ? VK_IMAGE_LAYOUT_GENERAL | ||
| 928 | : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; | ||
| 929 | zeta->Transition(image_layout, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, | ||
| 930 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 931 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); | ||
| 932 | } | 886 | } |
| 933 | } | 887 | } |
| 934 | 888 | ||
| @@ -1000,7 +954,7 @@ void RasterizerVulkan::EndTransformFeedback() { | |||
| 1000 | void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { | 954 | void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { |
| 1001 | const auto& regs = maxwell3d.regs; | 955 | const auto& regs = maxwell3d.regs; |
| 1002 | 956 | ||
| 1003 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 957 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 1004 | const auto& vertex_array = regs.vertex_array[index]; | 958 | const auto& vertex_array = regs.vertex_array[index]; |
| 1005 | if (!vertex_array.IsEnabled()) { | 959 | if (!vertex_array.IsEnabled()) { |
| 1006 | continue; | 960 | continue; |
| @@ -1009,7 +963,7 @@ void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { | |||
| 1009 | const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; | 963 | const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; |
| 1010 | 964 | ||
| 1011 | ASSERT(end >= start); | 965 | ASSERT(end >= start); |
| 1012 | const std::size_t size = end - start; | 966 | const size_t size = end - start; |
| 1013 | if (size == 0) { | 967 | if (size == 0) { |
| 1014 | buffer_bindings.AddVertexBinding(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE, 0); | 968 | buffer_bindings.AddVertexBinding(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE, 0); |
| 1015 | continue; | 969 | continue; |
| @@ -1070,7 +1024,7 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar | |||
| 1070 | } | 1024 | } |
| 1071 | } | 1025 | } |
| 1072 | 1026 | ||
| 1073 | void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage) { | 1027 | void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, size_t stage) { |
| 1074 | MICROPROFILE_SCOPE(Vulkan_ConstBuffers); | 1028 | MICROPROFILE_SCOPE(Vulkan_ConstBuffers); |
| 1075 | const auto& shader_stage = maxwell3d.state.shader_stages[stage]; | 1029 | const auto& shader_stage = maxwell3d.state.shader_stages[stage]; |
| 1076 | for (const auto& entry : entries.const_buffers) { | 1030 | for (const auto& entry : entries.const_buffers) { |
| @@ -1078,7 +1032,7 @@ void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, s | |||
| 1078 | } | 1032 | } |
| 1079 | } | 1033 | } |
| 1080 | 1034 | ||
| 1081 | void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage) { | 1035 | void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, size_t stage) { |
| 1082 | MICROPROFILE_SCOPE(Vulkan_GlobalBuffers); | 1036 | MICROPROFILE_SCOPE(Vulkan_GlobalBuffers); |
| 1083 | const auto& cbufs{maxwell3d.state.shader_stages[stage]}; | 1037 | const auto& cbufs{maxwell3d.state.shader_stages[stage]}; |
| 1084 | 1038 | ||
| @@ -1088,37 +1042,49 @@ void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, | |||
| 1088 | } | 1042 | } |
| 1089 | } | 1043 | } |
| 1090 | 1044 | ||
| 1091 | void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage) { | 1045 | void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, size_t stage) { |
| 1092 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1046 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1047 | const auto& regs = maxwell3d.regs; | ||
| 1048 | const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex; | ||
| 1093 | for (const auto& entry : entries.uniform_texels) { | 1049 | for (const auto& entry : entries.uniform_texels) { |
| 1094 | const auto image = GetTextureInfo(maxwell3d, entry, stage).tic; | 1050 | const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage); |
| 1095 | SetupUniformTexels(image, entry); | 1051 | image_view_indices.push_back(handle.image); |
| 1096 | } | 1052 | } |
| 1097 | } | 1053 | } |
| 1098 | 1054 | ||
| 1099 | void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage) { | 1055 | void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, size_t stage) { |
| 1100 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1056 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1057 | const auto& regs = maxwell3d.regs; | ||
| 1058 | const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex; | ||
| 1101 | for (const auto& entry : entries.samplers) { | 1059 | for (const auto& entry : entries.samplers) { |
| 1102 | for (std::size_t i = 0; i < entry.size; ++i) { | 1060 | for (size_t index = 0; index < entry.size; ++index) { |
| 1103 | const auto texture = GetTextureInfo(maxwell3d, entry, stage, i); | 1061 | const TextureHandle handle = |
| 1104 | SetupTexture(texture, entry); | 1062 | GetTextureInfo(maxwell3d, via_header_index, entry, stage, index); |
| 1063 | image_view_indices.push_back(handle.image); | ||
| 1064 | |||
| 1065 | Sampler* const sampler = texture_cache.GetGraphicsSampler(handle.sampler); | ||
| 1066 | sampler_handles.push_back(sampler->Handle()); | ||
| 1105 | } | 1067 | } |
| 1106 | } | 1068 | } |
| 1107 | } | 1069 | } |
| 1108 | 1070 | ||
| 1109 | void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage) { | 1071 | void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, size_t stage) { |
| 1110 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1072 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1073 | const auto& regs = maxwell3d.regs; | ||
| 1074 | const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex; | ||
| 1111 | for (const auto& entry : entries.storage_texels) { | 1075 | for (const auto& entry : entries.storage_texels) { |
| 1112 | const auto image = GetTextureInfo(maxwell3d, entry, stage).tic; | 1076 | const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage); |
| 1113 | SetupStorageTexel(image, entry); | 1077 | image_view_indices.push_back(handle.image); |
| 1114 | } | 1078 | } |
| 1115 | } | 1079 | } |
| 1116 | 1080 | ||
| 1117 | void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) { | 1081 | void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, size_t stage) { |
| 1118 | MICROPROFILE_SCOPE(Vulkan_Images); | 1082 | MICROPROFILE_SCOPE(Vulkan_Images); |
| 1083 | const auto& regs = maxwell3d.regs; | ||
| 1084 | const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex; | ||
| 1119 | for (const auto& entry : entries.images) { | 1085 | for (const auto& entry : entries.images) { |
| 1120 | const auto tic = GetTextureInfo(maxwell3d, entry, stage).tic; | 1086 | const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage); |
| 1121 | SetupImage(tic, entry); | 1087 | image_view_indices.push_back(handle.image); |
| 1122 | } | 1088 | } |
| 1123 | } | 1089 | } |
| 1124 | 1090 | ||
| @@ -1128,11 +1094,12 @@ void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) { | |||
| 1128 | for (const auto& entry : entries.const_buffers) { | 1094 | for (const auto& entry : entries.const_buffers) { |
| 1129 | const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; | 1095 | const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; |
| 1130 | const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value(); | 1096 | const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value(); |
| 1131 | Tegra::Engines::ConstBufferInfo buffer; | 1097 | const Tegra::Engines::ConstBufferInfo info{ |
| 1132 | buffer.address = config.Address(); | 1098 | .address = config.Address(), |
| 1133 | buffer.size = config.size; | 1099 | .size = config.size, |
| 1134 | buffer.enabled = mask[entry.GetIndex()]; | 1100 | .enabled = mask[entry.GetIndex()], |
| 1135 | SetupConstBuffer(entry, buffer); | 1101 | }; |
| 1102 | SetupConstBuffer(entry, info); | ||
| 1136 | } | 1103 | } |
| 1137 | } | 1104 | } |
| 1138 | 1105 | ||
| @@ -1147,35 +1114,46 @@ void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) { | |||
| 1147 | 1114 | ||
| 1148 | void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) { | 1115 | void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) { |
| 1149 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1116 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1117 | const bool via_header_index = kepler_compute.launch_description.linked_tsc; | ||
| 1150 | for (const auto& entry : entries.uniform_texels) { | 1118 | for (const auto& entry : entries.uniform_texels) { |
| 1151 | const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; | 1119 | const TextureHandle handle = |
| 1152 | SetupUniformTexels(image, entry); | 1120 | GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX); |
| 1121 | image_view_indices.push_back(handle.image); | ||
| 1153 | } | 1122 | } |
| 1154 | } | 1123 | } |
| 1155 | 1124 | ||
| 1156 | void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) { | 1125 | void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) { |
| 1157 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1126 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1127 | const bool via_header_index = kepler_compute.launch_description.linked_tsc; | ||
| 1158 | for (const auto& entry : entries.samplers) { | 1128 | for (const auto& entry : entries.samplers) { |
| 1159 | for (std::size_t i = 0; i < entry.size; ++i) { | 1129 | for (size_t index = 0; index < entry.size; ++index) { |
| 1160 | const auto texture = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex, i); | 1130 | const TextureHandle handle = GetTextureInfo(kepler_compute, via_header_index, entry, |
| 1161 | SetupTexture(texture, entry); | 1131 | COMPUTE_SHADER_INDEX, index); |
| 1132 | image_view_indices.push_back(handle.image); | ||
| 1133 | |||
| 1134 | Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler); | ||
| 1135 | sampler_handles.push_back(sampler->Handle()); | ||
| 1162 | } | 1136 | } |
| 1163 | } | 1137 | } |
| 1164 | } | 1138 | } |
| 1165 | 1139 | ||
| 1166 | void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) { | 1140 | void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) { |
| 1167 | MICROPROFILE_SCOPE(Vulkan_Textures); | 1141 | MICROPROFILE_SCOPE(Vulkan_Textures); |
| 1142 | const bool via_header_index = kepler_compute.launch_description.linked_tsc; | ||
| 1168 | for (const auto& entry : entries.storage_texels) { | 1143 | for (const auto& entry : entries.storage_texels) { |
| 1169 | const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; | 1144 | const TextureHandle handle = |
| 1170 | SetupStorageTexel(image, entry); | 1145 | GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX); |
| 1146 | image_view_indices.push_back(handle.image); | ||
| 1171 | } | 1147 | } |
| 1172 | } | 1148 | } |
| 1173 | 1149 | ||
| 1174 | void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { | 1150 | void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { |
| 1175 | MICROPROFILE_SCOPE(Vulkan_Images); | 1151 | MICROPROFILE_SCOPE(Vulkan_Images); |
| 1152 | const bool via_header_index = kepler_compute.launch_description.linked_tsc; | ||
| 1176 | for (const auto& entry : entries.images) { | 1153 | for (const auto& entry : entries.images) { |
| 1177 | const auto tic = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; | 1154 | const TextureHandle handle = |
| 1178 | SetupImage(tic, entry); | 1155 | GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX); |
| 1156 | image_view_indices.push_back(handle.image); | ||
| 1179 | } | 1157 | } |
| 1180 | } | 1158 | } |
| 1181 | 1159 | ||
| @@ -1186,14 +1164,12 @@ void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry, | |||
| 1186 | update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE); | 1164 | update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE); |
| 1187 | return; | 1165 | return; |
| 1188 | } | 1166 | } |
| 1189 | |||
| 1190 | // Align the size to avoid bad std140 interactions | 1167 | // Align the size to avoid bad std140 interactions |
| 1191 | const std::size_t size = | 1168 | const size_t size = Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float)); |
| 1192 | Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float)); | ||
| 1193 | ASSERT(size <= MaxConstbufferSize); | 1169 | ASSERT(size <= MaxConstbufferSize); |
| 1194 | 1170 | ||
| 1195 | const auto info = | 1171 | const u64 alignment = device.GetUniformBufferAlignment(); |
| 1196 | buffer_cache.UploadMemory(buffer.address, size, device.GetUniformBufferAlignment()); | 1172 | const auto info = buffer_cache.UploadMemory(buffer.address, size, alignment); |
| 1197 | update_descriptor_queue.AddBuffer(info.handle, info.offset, size); | 1173 | update_descriptor_queue.AddBuffer(info.handle, info.offset, size); |
| 1198 | } | 1174 | } |
| 1199 | 1175 | ||
| @@ -1206,7 +1182,7 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd | |||
| 1206 | // because Vulkan doesn't like empty buffers. | 1182 | // because Vulkan doesn't like empty buffers. |
| 1207 | // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the | 1183 | // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the |
| 1208 | // default buffer. | 1184 | // default buffer. |
| 1209 | static constexpr std::size_t dummy_size = 4; | 1185 | static constexpr size_t dummy_size = 4; |
| 1210 | const auto info = buffer_cache.GetEmptyBuffer(dummy_size); | 1186 | const auto info = buffer_cache.GetEmptyBuffer(dummy_size); |
| 1211 | update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size); | 1187 | update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size); |
| 1212 | return; | 1188 | return; |
| @@ -1217,55 +1193,6 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd | |||
| 1217 | update_descriptor_queue.AddBuffer(info.handle, info.offset, size); | 1193 | update_descriptor_queue.AddBuffer(info.handle, info.offset, size); |
| 1218 | } | 1194 | } |
| 1219 | 1195 | ||
| 1220 | void RasterizerVulkan::SetupUniformTexels(const Tegra::Texture::TICEntry& tic, | ||
| 1221 | const UniformTexelEntry& entry) { | ||
| 1222 | const auto view = texture_cache.GetTextureSurface(tic, entry); | ||
| 1223 | ASSERT(view->IsBufferView()); | ||
| 1224 | |||
| 1225 | update_descriptor_queue.AddTexelBuffer(view->GetBufferView()); | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | void RasterizerVulkan::SetupTexture(const Tegra::Texture::FullTextureInfo& texture, | ||
| 1229 | const SamplerEntry& entry) { | ||
| 1230 | auto view = texture_cache.GetTextureSurface(texture.tic, entry); | ||
| 1231 | ASSERT(!view->IsBufferView()); | ||
| 1232 | |||
| 1233 | const VkImageView image_view = view->GetImageView(texture.tic.x_source, texture.tic.y_source, | ||
| 1234 | texture.tic.z_source, texture.tic.w_source); | ||
| 1235 | const auto sampler = sampler_cache.GetSampler(texture.tsc); | ||
| 1236 | update_descriptor_queue.AddSampledImage(sampler, image_view); | ||
| 1237 | |||
| 1238 | VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout(); | ||
| 1239 | *image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; | ||
| 1240 | sampled_views.push_back(ImageView{std::move(view), image_layout}); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | void RasterizerVulkan::SetupStorageTexel(const Tegra::Texture::TICEntry& tic, | ||
| 1244 | const StorageTexelEntry& entry) { | ||
| 1245 | const auto view = texture_cache.GetImageSurface(tic, entry); | ||
| 1246 | ASSERT(view->IsBufferView()); | ||
| 1247 | |||
| 1248 | update_descriptor_queue.AddTexelBuffer(view->GetBufferView()); | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry) { | ||
| 1252 | auto view = texture_cache.GetImageSurface(tic, entry); | ||
| 1253 | |||
| 1254 | if (entry.is_written) { | ||
| 1255 | view->MarkAsModified(texture_cache.Tick()); | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | UNIMPLEMENTED_IF(tic.IsBuffer()); | ||
| 1259 | |||
| 1260 | const VkImageView image_view = | ||
| 1261 | view->GetImageView(tic.x_source, tic.y_source, tic.z_source, tic.w_source); | ||
| 1262 | update_descriptor_queue.AddImage(image_view); | ||
| 1263 | |||
| 1264 | VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout(); | ||
| 1265 | *image_layout = VK_IMAGE_LAYOUT_GENERAL; | ||
| 1266 | image_views.push_back(ImageView{std::move(view), image_layout}); | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) { | 1196 | void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) { |
| 1270 | if (!state_tracker.TouchViewports()) { | 1197 | if (!state_tracker.TouchViewports()) { |
| 1271 | return; | 1198 | return; |
| @@ -1457,8 +1384,8 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& | |||
| 1457 | }); | 1384 | }); |
| 1458 | } | 1385 | } |
| 1459 | 1386 | ||
| 1460 | std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const { | 1387 | size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const { |
| 1461 | std::size_t size = CalculateVertexArraysSize(); | 1388 | size_t size = CalculateVertexArraysSize(); |
| 1462 | if (is_indexed) { | 1389 | if (is_indexed) { |
| 1463 | size = Common::AlignUp(size, 4) + CalculateIndexBufferSize(); | 1390 | size = Common::AlignUp(size, 4) + CalculateIndexBufferSize(); |
| 1464 | } | 1391 | } |
| @@ -1466,15 +1393,15 @@ std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) | |||
| 1466 | return size; | 1393 | return size; |
| 1467 | } | 1394 | } |
| 1468 | 1395 | ||
| 1469 | std::size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const { | 1396 | size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const { |
| 1470 | return Tegra::Engines::KeplerCompute::NumConstBuffers * | 1397 | return Tegra::Engines::KeplerCompute::NumConstBuffers * |
| 1471 | (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment()); | 1398 | (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment()); |
| 1472 | } | 1399 | } |
| 1473 | 1400 | ||
| 1474 | std::size_t RasterizerVulkan::CalculateVertexArraysSize() const { | 1401 | size_t RasterizerVulkan::CalculateVertexArraysSize() const { |
| 1475 | const auto& regs = maxwell3d.regs; | 1402 | const auto& regs = maxwell3d.regs; |
| 1476 | 1403 | ||
| 1477 | std::size_t size = 0; | 1404 | size_t size = 0; |
| 1478 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { | 1405 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 1479 | // This implementation assumes that all attributes are used in the shader. | 1406 | // This implementation assumes that all attributes are used in the shader. |
| 1480 | const GPUVAddr start{regs.vertex_array[index].StartAddress()}; | 1407 | const GPUVAddr start{regs.vertex_array[index].StartAddress()}; |
| @@ -1486,12 +1413,12 @@ std::size_t RasterizerVulkan::CalculateVertexArraysSize() const { | |||
| 1486 | return size; | 1413 | return size; |
| 1487 | } | 1414 | } |
| 1488 | 1415 | ||
| 1489 | std::size_t RasterizerVulkan::CalculateIndexBufferSize() const { | 1416 | size_t RasterizerVulkan::CalculateIndexBufferSize() const { |
| 1490 | return static_cast<std::size_t>(maxwell3d.regs.index_array.count) * | 1417 | return static_cast<size_t>(maxwell3d.regs.index_array.count) * |
| 1491 | static_cast<std::size_t>(maxwell3d.regs.index_array.FormatSizeInBytes()); | 1418 | static_cast<size_t>(maxwell3d.regs.index_array.FormatSizeInBytes()); |
| 1492 | } | 1419 | } |
| 1493 | 1420 | ||
| 1494 | std::size_t RasterizerVulkan::CalculateConstBufferSize( | 1421 | size_t RasterizerVulkan::CalculateConstBufferSize( |
| 1495 | const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const { | 1422 | const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const { |
| 1496 | if (entry.IsIndirect()) { | 1423 | if (entry.IsIndirect()) { |
| 1497 | // Buffer is accessed indirectly, so upload the entire thing | 1424 | // Buffer is accessed indirectly, so upload the entire thing |
| @@ -1502,37 +1429,10 @@ std::size_t RasterizerVulkan::CalculateConstBufferSize( | |||
| 1502 | } | 1429 | } |
| 1503 | } | 1430 | } |
| 1504 | 1431 | ||
| 1505 | RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) const { | ||
| 1506 | const auto& regs = maxwell3d.regs; | ||
| 1507 | const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count); | ||
| 1508 | |||
| 1509 | RenderPassParams params; | ||
| 1510 | params.color_formats = {}; | ||
| 1511 | std::size_t color_texceptions = 0; | ||
| 1512 | |||
| 1513 | std::size_t index = 0; | ||
| 1514 | for (std::size_t rt = 0; rt < num_attachments; ++rt) { | ||
| 1515 | const auto& rendertarget = regs.rt[rt]; | ||
| 1516 | if (rendertarget.Address() == 0 || rendertarget.format == Tegra::RenderTargetFormat::NONE) { | ||
| 1517 | continue; | ||
| 1518 | } | ||
| 1519 | params.color_formats[index] = static_cast<u8>(rendertarget.format); | ||
| 1520 | color_texceptions |= (texceptions[rt] ? 1ULL : 0ULL) << index; | ||
| 1521 | ++index; | ||
| 1522 | } | ||
| 1523 | params.num_color_attachments = static_cast<u8>(index); | ||
| 1524 | params.texceptions = static_cast<u8>(color_texceptions); | ||
| 1525 | |||
| 1526 | params.zeta_format = regs.zeta_enable ? static_cast<u8>(regs.zeta.format) : 0; | ||
| 1527 | params.zeta_texception = texceptions[ZETA_TEXCEPTION_INDEX]; | ||
| 1528 | return params; | ||
| 1529 | } | ||
| 1530 | |||
| 1531 | VkBuffer RasterizerVulkan::DefaultBuffer() { | 1432 | VkBuffer RasterizerVulkan::DefaultBuffer() { |
| 1532 | if (default_buffer) { | 1433 | if (default_buffer) { |
| 1533 | return *default_buffer; | 1434 | return *default_buffer; |
| 1534 | } | 1435 | } |
| 1535 | |||
| 1536 | default_buffer = device.GetLogical().CreateBuffer({ | 1436 | default_buffer = device.GetLogical().CreateBuffer({ |
| 1537 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 1437 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 1538 | .pNext = nullptr, | 1438 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 30ec58eb4..990f9e031 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,10 +24,9 @@ | |||
| 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" | 32 | #include "video_core/renderer_vulkan/wrapper.h" |
| @@ -49,60 +48,9 @@ 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_, |
| @@ -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,23 +117,8 @@ private: | |||
| 160 | bool is_indexed = 0; | 117 | bool is_indexed = 0; |
| 161 | }; | 118 | }; |
| 162 | 119 | ||
| 163 | using ColorAttachments = std::array<View, Maxwell::NumRenderTargets>; | ||
| 164 | using ZetaAttachment = View; | ||
| 165 | |||
| 166 | using Texceptions = std::bitset<Maxwell::NumRenderTargets + 1>; | ||
| 167 | |||
| 168 | static constexpr std::size_t ZETA_TEXCEPTION_INDEX = 8; | ||
| 169 | static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float); | ||
| 170 | |||
| 171 | void FlushWork(); | 120 | void FlushWork(); |
| 172 | 121 | ||
| 173 | /// @brief Updates the currently bound attachments | ||
| 174 | /// @param is_clear True when the framebuffer is updated as a clear | ||
| 175 | /// @return Bitfield of attachments being used as sampled textures | ||
| 176 | Texceptions UpdateAttachments(bool is_clear); | ||
| 177 | |||
| 178 | std::tuple<VkFramebuffer, VkExtent2D> ConfigureFramebuffers(VkRenderPass renderpass); | ||
| 179 | |||
| 180 | /// Setups geometry buffers and state. | 122 | /// Setups geometry buffers and state. |
| 181 | DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings, | 123 | DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings, |
| 182 | bool is_indexed, bool is_instanced); | 124 | bool is_indexed, bool is_instanced); |
| @@ -184,17 +126,12 @@ private: | |||
| 184 | /// Setup descriptors in the graphics pipeline. | 126 | /// Setup descriptors in the graphics pipeline. |
| 185 | void SetupShaderDescriptors(const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders); | 127 | void SetupShaderDescriptors(const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders); |
| 186 | 128 | ||
| 187 | void SetupImageTransitions(Texceptions texceptions, const ColorAttachments& color, | ||
| 188 | const ZetaAttachment& zeta); | ||
| 189 | |||
| 190 | void UpdateDynamicStates(); | 129 | void UpdateDynamicStates(); |
| 191 | 130 | ||
| 192 | void BeginTransformFeedback(); | 131 | void BeginTransformFeedback(); |
| 193 | 132 | ||
| 194 | void EndTransformFeedback(); | 133 | void EndTransformFeedback(); |
| 195 | 134 | ||
| 196 | bool WalkAttachmentOverlaps(const CachedSurfaceView& attachment); | ||
| 197 | |||
| 198 | void SetupVertexArrays(BufferBindings& buffer_bindings); | 135 | void SetupVertexArrays(BufferBindings& buffer_bindings); |
| 199 | 136 | ||
| 200 | void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed); | 137 | void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed); |
| @@ -240,14 +177,6 @@ private: | |||
| 240 | 177 | ||
| 241 | void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address); | 178 | void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address); |
| 242 | 179 | ||
| 243 | void SetupUniformTexels(const Tegra::Texture::TICEntry& image, const UniformTexelEntry& entry); | ||
| 244 | |||
| 245 | void SetupTexture(const Tegra::Texture::FullTextureInfo& texture, const SamplerEntry& entry); | ||
| 246 | |||
| 247 | void SetupStorageTexel(const Tegra::Texture::TICEntry& tic, const StorageTexelEntry& entry); | ||
| 248 | |||
| 249 | void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry); | ||
| 250 | |||
| 251 | void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs); | 180 | void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs); |
| 252 | void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs); | 181 | void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs); |
| 253 | void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs); | 182 | void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs); |
| @@ -264,18 +193,16 @@ private: | |||
| 264 | void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); | 193 | void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); |
| 265 | void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); | 194 | void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); |
| 266 | 195 | ||
| 267 | std::size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const; | 196 | size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const; |
| 268 | |||
| 269 | std::size_t CalculateComputeStreamBufferSize() const; | ||
| 270 | 197 | ||
| 271 | std::size_t CalculateVertexArraysSize() const; | 198 | size_t CalculateComputeStreamBufferSize() const; |
| 272 | 199 | ||
| 273 | std::size_t CalculateIndexBufferSize() const; | 200 | size_t CalculateVertexArraysSize() const; |
| 274 | 201 | ||
| 275 | std::size_t CalculateConstBufferSize(const ConstBufferEntry& entry, | 202 | size_t CalculateIndexBufferSize() const; |
| 276 | const Tegra::Engines::ConstBufferInfo& buffer) const; | ||
| 277 | 203 | ||
| 278 | RenderPassParams GetRenderPassParams(Texceptions texceptions) const; | 204 | size_t CalculateConstBufferSize(const ConstBufferEntry& entry, |
| 205 | const Tegra::Engines::ConstBufferInfo& buffer) const; | ||
| 279 | 206 | ||
| 280 | VkBuffer DefaultBuffer(); | 207 | VkBuffer DefaultBuffer(); |
| 281 | 208 | ||
| @@ -290,18 +217,19 @@ private: | |||
| 290 | StateTracker& state_tracker; | 217 | StateTracker& state_tracker; |
| 291 | VKScheduler& scheduler; | 218 | VKScheduler& scheduler; |
| 292 | 219 | ||
| 220 | VKStreamBuffer stream_buffer; | ||
| 293 | VKStagingBufferPool staging_pool; | 221 | VKStagingBufferPool staging_pool; |
| 294 | VKDescriptorPool descriptor_pool; | 222 | VKDescriptorPool descriptor_pool; |
| 295 | VKUpdateDescriptorQueue update_descriptor_queue; | 223 | VKUpdateDescriptorQueue update_descriptor_queue; |
| 296 | VKRenderPassCache renderpass_cache; | 224 | BlitImageHelper blit_image; |
| 297 | QuadArrayPass quad_array_pass; | 225 | QuadArrayPass quad_array_pass; |
| 298 | QuadIndexedPass quad_indexed_pass; | 226 | QuadIndexedPass quad_indexed_pass; |
| 299 | Uint8Pass uint8_pass; | 227 | Uint8Pass uint8_pass; |
| 300 | 228 | ||
| 301 | VKTextureCache texture_cache; | 229 | TextureCacheRuntime texture_cache_runtime; |
| 230 | TextureCache texture_cache; | ||
| 302 | VKPipelineCache pipeline_cache; | 231 | VKPipelineCache pipeline_cache; |
| 303 | VKBufferCache buffer_cache; | 232 | VKBufferCache buffer_cache; |
| 304 | VKSamplerCache sampler_cache; | ||
| 305 | VKQueryCache query_cache; | 233 | VKQueryCache query_cache; |
| 306 | VKFenceManager fence_manager; | 234 | VKFenceManager fence_manager; |
| 307 | 235 | ||
| @@ -310,16 +238,11 @@ private: | |||
| 310 | vk::Event wfi_event; | 238 | vk::Event wfi_event; |
| 311 | VideoCommon::Shader::AsyncShaders async_shaders; | 239 | VideoCommon::Shader::AsyncShaders async_shaders; |
| 312 | 240 | ||
| 313 | ColorAttachments color_attachments; | 241 | boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices; |
| 314 | ZetaAttachment zeta_attachment; | 242 | std::array<VideoCommon::ImageViewId, MAX_IMAGE_VIEWS> image_view_ids; |
| 315 | 243 | boost::container::static_vector<VkSampler, MAX_TEXTURES> sampler_handles; | |
| 316 | std::vector<ImageView> sampled_views; | ||
| 317 | std::vector<ImageView> image_views; | ||
| 318 | 244 | ||
| 319 | u32 draw_counter = 0; | 245 | u32 draw_counter = 0; |
| 320 | |||
| 321 | // TODO(Rodrigo): Invalidate on image destruction | ||
| 322 | std::unordered_map<FramebufferCacheKey, vk::Framebuffer> framebuffer_cache; | ||
| 323 | }; | 246 | }; |
| 324 | 247 | ||
| 325 | } // 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 e812c7dd6..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 652ecef7b..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 b859691fa..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 3f22c4610..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..c104c6fe3 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 16 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 17 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 17 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 18 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 18 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 19 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | ||
| 19 | #include "video_core/renderer_vulkan/wrapper.h" | 20 | #include "video_core/renderer_vulkan/wrapper.h" |
| 20 | 21 | ||
| 21 | namespace Vulkan { | 22 | namespace Vulkan { |
| @@ -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 6d3a5da0b..0a36c8fad 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | namespace Vulkan { | 17 | namespace Vulkan { |
| 18 | 18 | ||
| 19 | class CommandPool; | 19 | class CommandPool; |
| 20 | class Framebuffer; | ||
| 20 | class MasterSemaphore; | 21 | class MasterSemaphore; |
| 21 | class StateTracker; | 22 | class StateTracker; |
| 22 | class VKDevice; | 23 | class VKDevice; |
| @@ -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_; |
| @@ -170,8 +173,6 @@ 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(); |
| @@ -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 72954d0e3..09d6f9f35 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -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: |
| @@ -119,7 +119,7 @@ spv::Dim GetSamplerDim(const Sampler& sampler) { | |||
| 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}; |
| @@ -980,7 +980,7 @@ private: | |||
| 980 | return binding; | 980 | return binding; |
| 981 | } | 981 | } |
| 982 | 982 | ||
| 983 | void DeclareImage(const Image& image, u32& binding) { | 983 | void DeclareImage(const ImageEntry& image, u32& binding) { |
| 984 | const auto [dim, arrayed] = GetImageDim(image); | 984 | const auto [dim, arrayed] = GetImageDim(image); |
| 985 | constexpr int depth = 0; | 985 | constexpr int depth = 0; |
| 986 | constexpr bool ms = false; | 986 | constexpr bool ms = false; |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h index df1812514..ad91ad5de 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h | |||
| @@ -21,10 +21,10 @@ class VKDevice; | |||
| 21 | namespace Vulkan { | 21 | namespace Vulkan { |
| 22 | 22 | ||
| 23 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 23 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 24 | using UniformTexelEntry = VideoCommon::Shader::Sampler; | 24 | using UniformTexelEntry = VideoCommon::Shader::SamplerEntry; |
| 25 | using SamplerEntry = VideoCommon::Shader::Sampler; | 25 | using SamplerEntry = VideoCommon::Shader::SamplerEntry; |
| 26 | using StorageTexelEntry = VideoCommon::Shader::Image; | 26 | using StorageTexelEntry = VideoCommon::Shader::ImageEntry; |
| 27 | using ImageEntry = VideoCommon::Shader::Image; | 27 | using ImageEntry = VideoCommon::Shader::ImageEntry; |
| 28 | 28 | ||
| 29 | constexpr u32 DESCRIPTOR_SET = 0; | 29 | constexpr u32 DESCRIPTOR_SET = 0; |
| 30 | 30 | ||
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp index c1a218d76..38a0be7f2 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp | |||
| @@ -13,18 +13,13 @@ | |||
| 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 VKDevice& 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..dce34a140 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.h +++ b/src/video_core/renderer_vulkan/vk_shader_util.h | |||
| @@ -4,6 +4,8 @@ | |||
| 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/renderer_vulkan/wrapper.h" |
| 9 | 11 | ||
| @@ -11,6 +13,6 @@ namespace Vulkan { | |||
| 11 | 13 | ||
| 12 | class VKDevice; | 14 | class VKDevice; |
| 13 | 15 | ||
| 14 | vk::ShaderModule BuildShader(const VKDevice& device, std::size_t code_size, const u8* code_data); | 16 | vk::ShaderModule BuildShader(const VKDevice& device, std::span<const u32> code); |
| 15 | 17 | ||
| 16 | } // namespace Vulkan | 18 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index 50164cc08..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 | ||
| @@ -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 1b59612b9..419cb154d 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp | |||
| @@ -19,6 +19,10 @@ 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 VKDevice& 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,7 +113,7 @@ 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; |
| @@ -127,7 +127,7 @@ void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) { | |||
| 127 | .pNext = nullptr, | 127 | .pNext = nullptr, |
| 128 | .flags = 0, | 128 | .flags = 0, |
| 129 | .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size), | 129 | .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size), |
| 130 | .usage = usage, | 130 | .usage = BUFFER_USAGE, |
| 131 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 131 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 132 | .queueFamilyIndexCount = 0, | 132 | .queueFamilyIndexCount = 0, |
| 133 | .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..1428f77bf 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.h +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h | |||
| @@ -5,7 +5,7 @@ | |||
| 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" |
| @@ -19,17 +19,15 @@ 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 VKDevice& 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,7 +47,7 @@ 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); |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index ae2e3322c..261808391 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -4,614 +4,1103 @@ | |||
| 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" | 13 | #include "video_core/renderer_vulkan/vk_device.h" |
| 20 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 21 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | ||
| 22 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 23 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 15 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 24 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 16 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 25 | #include "video_core/renderer_vulkan/wrapper.h" | 17 | #include "video_core/renderer_vulkan/wrapper.h" |
| 26 | #include "video_core/surface.h" | ||
| 27 | 18 | ||
| 28 | namespace Vulkan { | 19 | namespace Vulkan { |
| 29 | 20 | ||
| 30 | using VideoCore::MortonSwizzle; | 21 | using Tegra::Engines::Fermi2D; |
| 31 | using VideoCore::MortonSwizzleMode; | ||
| 32 | |||
| 33 | using Tegra::Texture::SwizzleSource; | 22 | using Tegra::Texture::SwizzleSource; |
| 34 | using VideoCore::Surface::PixelFormat; | 23 | using Tegra::Texture::TextureMipmapFilter; |
| 35 | using VideoCore::Surface::SurfaceTarget; | 24 | using VideoCommon::BufferImageCopy; |
| 25 | using VideoCommon::ImageInfo; | ||
| 26 | using VideoCommon::ImageType; | ||
| 27 | using VideoCommon::SubresourceRange; | ||
| 28 | using VideoCore::Surface::IsPixelFormatASTC; | ||
| 36 | 29 | ||
| 37 | namespace { | 30 | namespace { |
| 38 | 31 | ||
| 39 | VkImageType SurfaceTargetToImage(SurfaceTarget target) { | 32 | constexpr std::array ATTACHMENT_REFERENCES{ |
| 40 | switch (target) { | 33 | VkAttachmentReference{0, VK_IMAGE_LAYOUT_GENERAL}, |
| 41 | case SurfaceTarget::Texture1D: | 34 | VkAttachmentReference{1, VK_IMAGE_LAYOUT_GENERAL}, |
| 42 | case SurfaceTarget::Texture1DArray: | 35 | VkAttachmentReference{2, VK_IMAGE_LAYOUT_GENERAL}, |
| 36 | VkAttachmentReference{3, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 37 | VkAttachmentReference{4, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 38 | VkAttachmentReference{5, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 39 | VkAttachmentReference{6, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 40 | VkAttachmentReference{7, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 41 | VkAttachmentReference{8, VK_IMAGE_LAYOUT_GENERAL}, | ||
| 42 | }; | ||
| 43 | |||
| 44 | constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | ||
| 45 | if (color == std::array<float, 4>{0, 0, 0, 0}) { | ||
| 46 | return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; | ||
| 47 | } else if (color == std::array<float, 4>{0, 0, 0, 1}) { | ||
| 48 | return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; | ||
| 49 | } else if (color == std::array<float, 4>{1, 1, 1, 1}) { | ||
| 50 | return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; | ||
| 51 | } | ||
| 52 | if (color[0] + color[1] + color[2] > 1.35f) { | ||
| 53 | // If color elements are brighter than roughly 0.5 average, use white border | ||
| 54 | return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; | ||
| 55 | } else if (color[3] > 0.5f) { | ||
| 56 | return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; | ||
| 57 | } else { | ||
| 58 | return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | [[nodiscard]] VkImageType ConvertImageType(const ImageType type) { | ||
| 63 | switch (type) { | ||
| 64 | case ImageType::e1D: | ||
| 43 | return VK_IMAGE_TYPE_1D; | 65 | return VK_IMAGE_TYPE_1D; |
| 44 | case SurfaceTarget::Texture2D: | 66 | case ImageType::e2D: |
| 45 | case SurfaceTarget::Texture2DArray: | 67 | case ImageType::Linear: |
| 46 | case SurfaceTarget::TextureCubemap: | ||
| 47 | case SurfaceTarget::TextureCubeArray: | ||
| 48 | return VK_IMAGE_TYPE_2D; | 68 | return VK_IMAGE_TYPE_2D; |
| 49 | case SurfaceTarget::Texture3D: | 69 | case ImageType::e3D: |
| 50 | return VK_IMAGE_TYPE_3D; | 70 | return VK_IMAGE_TYPE_3D; |
| 51 | case SurfaceTarget::TextureBuffer: | 71 | case ImageType::Buffer: |
| 52 | UNREACHABLE(); | 72 | break; |
| 53 | return {}; | ||
| 54 | } | 73 | } |
| 55 | UNREACHABLE_MSG("Unknown texture target={}", target); | 74 | UNREACHABLE_MSG("Invalid image type={}", type); |
| 56 | return {}; | 75 | return {}; |
| 57 | } | 76 | } |
| 58 | 77 | ||
| 59 | VkImageAspectFlags PixelFormatToImageAspect(PixelFormat pixel_format) { | 78 | [[nodiscard]] VkSampleCountFlagBits ConvertSampleCount(u32 num_samples) { |
| 60 | if (pixel_format < PixelFormat::MaxColorFormat) { | 79 | switch (num_samples) { |
| 61 | return VK_IMAGE_ASPECT_COLOR_BIT; | 80 | case 1: |
| 62 | } else if (pixel_format < PixelFormat::MaxDepthFormat) { | 81 | return VK_SAMPLE_COUNT_1_BIT; |
| 63 | return VK_IMAGE_ASPECT_DEPTH_BIT; | 82 | case 2: |
| 64 | } else if (pixel_format < PixelFormat::MaxDepthStencilFormat) { | 83 | return VK_SAMPLE_COUNT_2_BIT; |
| 65 | return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; | 84 | case 4: |
| 66 | } else { | 85 | return VK_SAMPLE_COUNT_4_BIT; |
| 67 | UNREACHABLE_MSG("Invalid pixel format={}", pixel_format); | 86 | case 8: |
| 68 | return VK_IMAGE_ASPECT_COLOR_BIT; | 87 | return VK_SAMPLE_COUNT_8_BIT; |
| 88 | case 16: | ||
| 89 | return VK_SAMPLE_COUNT_16_BIT; | ||
| 90 | default: | ||
| 91 | UNREACHABLE_MSG("Invalid number of samples={}", num_samples); | ||
| 92 | return VK_SAMPLE_COUNT_1_BIT; | ||
| 69 | } | 93 | } |
| 70 | } | 94 | } |
| 71 | 95 | ||
| 72 | VkImageViewType GetImageViewType(SurfaceTarget target) { | 96 | [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const VKDevice& device, const ImageInfo& info) { |
| 73 | switch (target) { | 97 | const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, info.format); |
| 74 | case SurfaceTarget::Texture1D: | 98 | VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| 75 | return VK_IMAGE_VIEW_TYPE_1D; | 99 | if (info.type == ImageType::e2D && info.resources.layers >= 6 && |
| 76 | case SurfaceTarget::Texture2D: | 100 | info.size.width == info.size.height) { |
| 77 | return VK_IMAGE_VIEW_TYPE_2D; | 101 | 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 | } | 102 | } |
| 91 | UNREACHABLE(); | 103 | if (info.type == ImageType::e3D) { |
| 92 | return {}; | 104 | flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; |
| 93 | } | 105 | } |
| 94 | 106 | VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | | |
| 95 | vk::Buffer CreateBuffer(const VKDevice& device, const SurfaceParams& params, | 107 | VK_IMAGE_USAGE_SAMPLED_BIT; |
| 96 | std::size_t host_memory_size) { | 108 | if (format_info.attachable) { |
| 97 | // TODO(Rodrigo): Move texture buffer creation to the buffer cache | 109 | switch (VideoCore::Surface::GetFormatType(info.format)) { |
| 98 | return device.GetLogical().CreateBuffer({ | 110 | case VideoCore::Surface::SurfaceType::ColorTexture: |
| 99 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 111 | usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
| 112 | break; | ||
| 113 | case VideoCore::Surface::SurfaceType::Depth: | ||
| 114 | case VideoCore::Surface::SurfaceType::DepthStencil: | ||
| 115 | usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; | ||
| 116 | break; | ||
| 117 | default: | ||
| 118 | UNREACHABLE_MSG("Invalid surface type"); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | if (format_info.storage) { | ||
| 122 | usage |= VK_IMAGE_USAGE_STORAGE_BIT; | ||
| 123 | } | ||
| 124 | const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples); | ||
| 125 | return VkImageCreateInfo{ | ||
| 126 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | ||
| 100 | .pNext = nullptr, | 127 | .pNext = nullptr, |
| 101 | .flags = 0, | 128 | .flags = flags, |
| 102 | .size = static_cast<VkDeviceSize>(host_memory_size), | 129 | .imageType = ConvertImageType(info.type), |
| 103 | .usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | | 130 | .format = format_info.format, |
| 104 | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | | 131 | .extent = |
| 105 | VK_BUFFER_USAGE_TRANSFER_DST_BIT, | 132 | { |
| 133 | .width = info.size.width >> samples_x, | ||
| 134 | .height = info.size.height >> samples_y, | ||
| 135 | .depth = info.size.depth, | ||
| 136 | }, | ||
| 137 | .mipLevels = static_cast<u32>(info.resources.levels), | ||
| 138 | .arrayLayers = static_cast<u32>(info.resources.layers), | ||
| 139 | .samples = ConvertSampleCount(info.num_samples), | ||
| 140 | .tiling = VK_IMAGE_TILING_OPTIMAL, | ||
| 141 | .usage = usage, | ||
| 106 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 142 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 107 | .queueFamilyIndexCount = 0, | 143 | .queueFamilyIndexCount = 0, |
| 108 | .pQueueFamilyIndices = nullptr, | 144 | .pQueueFamilyIndices = nullptr, |
| 109 | }); | 145 | .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 | }; | 146 | }; |
| 127 | } | 147 | } |
| 128 | 148 | ||
| 129 | VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { | 149 | [[nodiscard]] vk::Image MakeImage(const VKDevice& device, const ImageInfo& info) { |
| 130 | ASSERT(!params.IsBuffer()); | 150 | if (info.type == ImageType::Buffer) { |
| 131 | 151 | return vk::Image{}; | |
| 132 | const auto [format, attachable, storage] = | 152 | } |
| 133 | MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, params.pixel_format); | 153 | return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info)); |
| 154 | } | ||
| 134 | 155 | ||
| 135 | VkImageCreateInfo ci{ | 156 | [[nodiscard]] vk::Buffer MakeBuffer(const VKDevice& device, const ImageInfo& info) { |
| 136 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 157 | if (info.type != ImageType::Buffer) { |
| 158 | return vk::Buffer{}; | ||
| 159 | } | ||
| 160 | const size_t bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format); | ||
| 161 | return device.GetLogical().CreateBuffer(VkBufferCreateInfo{ | ||
| 162 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 137 | .pNext = nullptr, | 163 | .pNext = nullptr, |
| 138 | .flags = 0, | 164 | .flags = 0, |
| 139 | .imageType = SurfaceTargetToImage(params.target), | 165 | .size = info.size.width * bytes_per_block, |
| 140 | .format = format, | 166 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 141 | .extent = {}, | 167 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | |
| 142 | .mipLevels = params.num_levels, | 168 | 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, | 169 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 149 | .queueFamilyIndexCount = 0, | 170 | .queueFamilyIndexCount = 0, |
| 150 | .pQueueFamilyIndices = nullptr, | 171 | .pQueueFamilyIndices = nullptr, |
| 151 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 172 | }); |
| 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 | } | 173 | } |
| 182 | 174 | ||
| 183 | u32 EncodeSwizzle(SwizzleSource x_source, SwizzleSource y_source, SwizzleSource z_source, | 175 | [[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { |
| 184 | SwizzleSource w_source) { | 176 | switch (VideoCore::Surface::GetFormatType(format)) { |
| 185 | return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) | | 177 | case VideoCore::Surface::SurfaceType::ColorTexture: |
| 186 | (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source); | 178 | return VK_IMAGE_ASPECT_COLOR_BIT; |
| 179 | case VideoCore::Surface::SurfaceType::Depth: | ||
| 180 | return VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 181 | case VideoCore::Surface::SurfaceType::DepthStencil: | ||
| 182 | return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; | ||
| 183 | default: | ||
| 184 | UNREACHABLE_MSG("Invalid surface type"); | ||
| 185 | return VkImageAspectFlags{}; | ||
| 186 | } | ||
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | } // Anonymous namespace | 189 | [[nodiscard]] VkImageAspectFlags ImageViewAspectMask(const VideoCommon::ImageViewInfo& info) { |
| 190 | 190 | if (info.IsRenderTarget()) { | |
| 191 | CachedSurface::CachedSurface(const VKDevice& device_, VKMemoryManager& memory_manager_, | 191 | 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 | } | 192 | } |
| 212 | 193 | const bool is_first = info.Swizzle()[0] == SwizzleSource::R; | |
| 213 | // TODO(Rodrigo): Move this to a virtual function. | 194 | switch (info.format) { |
| 214 | u32 num_layers = 1; | 195 | case PixelFormat::D24_UNORM_S8_UINT: |
| 215 | if (params.is_layered || params.target == SurfaceTarget::Texture3D) { | 196 | case PixelFormat::D32_FLOAT_S8_UINT: |
| 216 | num_layers = params.depth; | 197 | return is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT; |
| 198 | case PixelFormat::S8_UINT_D24_UNORM: | ||
| 199 | return is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 200 | case PixelFormat::D16_UNORM: | ||
| 201 | case PixelFormat::D32_FLOAT: | ||
| 202 | return VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 203 | default: | ||
| 204 | return VK_IMAGE_ASPECT_COLOR_BIT; | ||
| 217 | } | 205 | } |
| 218 | main_view = CreateView(ViewParams(params.target, 0, num_layers, 0, params.num_levels)); | ||
| 219 | } | 206 | } |
| 220 | 207 | ||
| 221 | CachedSurface::~CachedSurface() = default; | 208 | [[nodiscard]] VkAttachmentDescription AttachmentDescription(const VKDevice& device, |
| 222 | 209 | const ImageView* image_view) { | |
| 223 | void CachedSurface::UploadTexture(const std::vector<u8>& staging_buffer) { | 210 | const auto pixel_format = image_view->format; |
| 224 | // To upload data we have to be outside of a renderpass | 211 | return VkAttachmentDescription{ |
| 225 | scheduler.RequestOutsideRenderPassOperationContext(); | 212 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, |
| 213 | .format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format).format, | ||
| 214 | .samples = image_view->Samples(), | ||
| 215 | .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 216 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 217 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 218 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 219 | .initialLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 220 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 221 | }; | ||
| 222 | } | ||
| 226 | 223 | ||
| 227 | if (params.IsBuffer()) { | 224 | [[nodiscard]] VkComponentSwizzle ComponentSwizzle(SwizzleSource swizzle) { |
| 228 | UploadBuffer(staging_buffer); | 225 | switch (swizzle) { |
| 229 | } else { | 226 | case SwizzleSource::Zero: |
| 230 | UploadImage(staging_buffer); | 227 | return VK_COMPONENT_SWIZZLE_ZERO; |
| 228 | case SwizzleSource::R: | ||
| 229 | return VK_COMPONENT_SWIZZLE_R; | ||
| 230 | case SwizzleSource::G: | ||
| 231 | return VK_COMPONENT_SWIZZLE_G; | ||
| 232 | case SwizzleSource::B: | ||
| 233 | return VK_COMPONENT_SWIZZLE_B; | ||
| 234 | case SwizzleSource::A: | ||
| 235 | return VK_COMPONENT_SWIZZLE_A; | ||
| 236 | case SwizzleSource::OneFloat: | ||
| 237 | case SwizzleSource::OneInt: | ||
| 238 | return VK_COMPONENT_SWIZZLE_ONE; | ||
| 231 | } | 239 | } |
| 240 | UNREACHABLE_MSG("Invalid swizzle={}", swizzle); | ||
| 241 | return VK_COMPONENT_SWIZZLE_ZERO; | ||
| 232 | } | 242 | } |
| 233 | 243 | ||
| 234 | void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { | 244 | [[nodiscard]] VkImageViewType ImageViewType(VideoCommon::ImageViewType type) { |
| 235 | UNIMPLEMENTED_IF(params.IsBuffer()); | 245 | switch (type) { |
| 236 | 246 | case VideoCommon::ImageViewType::e1D: | |
| 237 | if (params.pixel_format == PixelFormat::A1B5G5R5_UNORM) { | 247 | return VK_IMAGE_VIEW_TYPE_1D; |
| 238 | LOG_WARNING(Render_Vulkan, "A1B5G5R5 flushing is stubbed"); | 248 | case VideoCommon::ImageViewType::e2D: |
| 249 | return VK_IMAGE_VIEW_TYPE_2D; | ||
| 250 | case VideoCommon::ImageViewType::Cube: | ||
| 251 | return VK_IMAGE_VIEW_TYPE_CUBE; | ||
| 252 | case VideoCommon::ImageViewType::e3D: | ||
| 253 | return VK_IMAGE_VIEW_TYPE_3D; | ||
| 254 | case VideoCommon::ImageViewType::e1DArray: | ||
| 255 | return VK_IMAGE_VIEW_TYPE_1D_ARRAY; | ||
| 256 | case VideoCommon::ImageViewType::e2DArray: | ||
| 257 | return VK_IMAGE_VIEW_TYPE_2D_ARRAY; | ||
| 258 | case VideoCommon::ImageViewType::CubeArray: | ||
| 259 | return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; | ||
| 260 | case VideoCommon::ImageViewType::Rect: | ||
| 261 | LOG_WARNING(Render_Vulkan, "Unnormalized image view type not supported"); | ||
| 262 | return VK_IMAGE_VIEW_TYPE_2D; | ||
| 263 | case VideoCommon::ImageViewType::Buffer: | ||
| 264 | UNREACHABLE_MSG("Texture buffers can't be image views"); | ||
| 265 | return VK_IMAGE_VIEW_TYPE_1D; | ||
| 239 | } | 266 | } |
| 267 | UNREACHABLE_MSG("Invalid image view type={}", type); | ||
| 268 | return VK_IMAGE_VIEW_TYPE_2D; | ||
| 269 | } | ||
| 240 | 270 | ||
| 241 | // We can't copy images to buffers inside a renderpass | 271 | [[nodiscard]] VkImageSubresourceLayers MakeImageSubresourceLayers( |
| 242 | scheduler.RequestOutsideRenderPassOperationContext(); | 272 | VideoCommon::SubresourceLayers subresource, VkImageAspectFlags aspect_mask) { |
| 273 | return VkImageSubresourceLayers{ | ||
| 274 | .aspectMask = aspect_mask, | ||
| 275 | .mipLevel = static_cast<u32>(subresource.base_level), | ||
| 276 | .baseArrayLayer = static_cast<u32>(subresource.base_layer), | ||
| 277 | .layerCount = static_cast<u32>(subresource.num_layers), | ||
| 278 | }; | ||
| 279 | } | ||
| 243 | 280 | ||
| 244 | FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, | 281 | [[nodiscard]] VkOffset3D MakeOffset3D(VideoCommon::Offset3D offset3d) { |
| 245 | VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); | 282 | return VkOffset3D{ |
| 283 | .x = offset3d.x, | ||
| 284 | .y = offset3d.y, | ||
| 285 | .z = offset3d.z, | ||
| 286 | }; | ||
| 287 | } | ||
| 246 | 288 | ||
| 247 | const auto& unused_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); | 289 | [[nodiscard]] VkExtent3D MakeExtent3D(VideoCommon::Extent3D extent3d) { |
| 248 | // TODO(Rodrigo): Do this in a single copy | 290 | return VkExtent3D{ |
| 249 | for (u32 level = 0; level < params.num_levels; ++level) { | 291 | .width = static_cast<u32>(extent3d.width), |
| 250 | scheduler.Record([image = *image->GetHandle(), buffer = *unused_buffer.handle, | 292 | .height = static_cast<u32>(extent3d.height), |
| 251 | copy = GetBufferImageCopy(level)](vk::CommandBuffer cmdbuf) { | 293 | .depth = static_cast<u32>(extent3d.depth), |
| 252 | cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy); | 294 | }; |
| 253 | }); | 295 | } |
| 254 | } | ||
| 255 | scheduler.Finish(); | ||
| 256 | 296 | ||
| 257 | // TODO(Rodrigo): Use an intern buffer for staging buffers and avoid this unnecessary memcpy. | 297 | [[nodiscard]] VkImageCopy MakeImageCopy(const VideoCommon::ImageCopy& copy, |
| 258 | std::memcpy(staging_buffer.data(), unused_buffer.commit->Map(host_memory_size), | 298 | VkImageAspectFlags aspect_mask) noexcept { |
| 259 | host_memory_size); | 299 | return VkImageCopy{ |
| 300 | .srcSubresource = MakeImageSubresourceLayers(copy.src_subresource, aspect_mask), | ||
| 301 | .srcOffset = MakeOffset3D(copy.src_offset), | ||
| 302 | .dstSubresource = MakeImageSubresourceLayers(copy.dst_subresource, aspect_mask), | ||
| 303 | .dstOffset = MakeOffset3D(copy.dst_offset), | ||
| 304 | .extent = MakeExtent3D(copy.extent), | ||
| 305 | }; | ||
| 260 | } | 306 | } |
| 261 | 307 | ||
| 262 | void CachedSurface::DecorateSurfaceName() { | 308 | [[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies( |
| 263 | // TODO(Rodrigo): Add name decorations | 309 | std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) { |
| 310 | std::vector<VkBufferCopy> result(copies.size()); | ||
| 311 | std::ranges::transform( | ||
| 312 | copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) { | ||
| 313 | return VkBufferCopy{ | ||
| 314 | .srcOffset = static_cast<VkDeviceSize>(copy.src_offset + buffer_offset), | ||
| 315 | .dstOffset = static_cast<VkDeviceSize>(copy.dst_offset), | ||
| 316 | .size = static_cast<VkDeviceSize>(copy.size), | ||
| 317 | }; | ||
| 318 | }); | ||
| 319 | return result; | ||
| 264 | } | 320 | } |
| 265 | 321 | ||
| 266 | View CachedSurface::CreateView(const ViewParams& view_params) { | 322 | [[nodiscard]] std::vector<VkBufferImageCopy> TransformBufferImageCopies( |
| 267 | // TODO(Rodrigo): Add name decorations | 323 | std::span<const BufferImageCopy> copies, size_t buffer_offset, VkImageAspectFlags aspect_mask) { |
| 268 | return views[view_params] = std::make_shared<CachedSurfaceView>(device, *this, view_params); | 324 | struct Maker { |
| 325 | VkBufferImageCopy operator()(const BufferImageCopy& copy) const { | ||
| 326 | return VkBufferImageCopy{ | ||
| 327 | .bufferOffset = copy.buffer_offset + buffer_offset, | ||
| 328 | .bufferRowLength = copy.buffer_row_length, | ||
| 329 | .bufferImageHeight = copy.buffer_image_height, | ||
| 330 | .imageSubresource = | ||
| 331 | { | ||
| 332 | .aspectMask = aspect_mask, | ||
| 333 | .mipLevel = static_cast<u32>(copy.image_subresource.base_level), | ||
| 334 | .baseArrayLayer = static_cast<u32>(copy.image_subresource.base_layer), | ||
| 335 | .layerCount = static_cast<u32>(copy.image_subresource.num_layers), | ||
| 336 | }, | ||
| 337 | .imageOffset = | ||
| 338 | { | ||
| 339 | .x = copy.image_offset.x, | ||
| 340 | .y = copy.image_offset.y, | ||
| 341 | .z = copy.image_offset.z, | ||
| 342 | }, | ||
| 343 | .imageExtent = | ||
| 344 | { | ||
| 345 | .width = copy.image_extent.width, | ||
| 346 | .height = copy.image_extent.height, | ||
| 347 | .depth = copy.image_extent.depth, | ||
| 348 | }, | ||
| 349 | }; | ||
| 350 | } | ||
| 351 | size_t buffer_offset; | ||
| 352 | VkImageAspectFlags aspect_mask; | ||
| 353 | }; | ||
| 354 | if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | ||
| 355 | std::vector<VkBufferImageCopy> result(copies.size() * 2); | ||
| 356 | std::ranges::transform(copies, result.begin(), | ||
| 357 | Maker{buffer_offset, VK_IMAGE_ASPECT_DEPTH_BIT}); | ||
| 358 | std::ranges::transform(copies, result.begin() + copies.size(), | ||
| 359 | Maker{buffer_offset, VK_IMAGE_ASPECT_STENCIL_BIT}); | ||
| 360 | return result; | ||
| 361 | } else { | ||
| 362 | std::vector<VkBufferImageCopy> result(copies.size()); | ||
| 363 | std::ranges::transform(copies, result.begin(), Maker{buffer_offset, aspect_mask}); | ||
| 364 | return result; | ||
| 365 | } | ||
| 269 | } | 366 | } |
| 270 | 367 | ||
| 271 | void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) { | 368 | [[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(VkImageAspectFlags aspect_mask, |
| 272 | const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); | 369 | const SubresourceRange& range) { |
| 273 | std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); | 370 | return VkImageSubresourceRange{ |
| 371 | .aspectMask = aspect_mask, | ||
| 372 | .baseMipLevel = static_cast<u32>(range.base.level), | ||
| 373 | .levelCount = static_cast<u32>(range.extent.levels), | ||
| 374 | .baseArrayLayer = static_cast<u32>(range.base.layer), | ||
| 375 | .layerCount = static_cast<u32>(range.extent.layers), | ||
| 376 | }; | ||
| 377 | } | ||
| 274 | 378 | ||
| 275 | scheduler.Record([src_buffer = *src_buffer.handle, dst_buffer = *buffer, | 379 | [[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(const ImageView* image_view) { |
| 276 | size = host_memory_size](vk::CommandBuffer cmdbuf) { | 380 | SubresourceRange range = image_view->range; |
| 277 | VkBufferCopy copy; | 381 | if (True(image_view->flags & VideoCommon::ImageViewFlagBits::Slice)) { |
| 278 | copy.srcOffset = 0; | 382 | // Slice image views always affect a single layer, but their subresource range corresponds |
| 279 | copy.dstOffset = 0; | 383 | // to the slice. Override the value to affect a single layer. |
| 280 | copy.size = size; | 384 | range.base.layer = 0; |
| 281 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); | 385 | range.extent.layers = 1; |
| 386 | } | ||
| 387 | return MakeSubresourceRange(ImageAspectMask(image_view->format), range); | ||
| 388 | } | ||
| 282 | 389 | ||
| 283 | VkBufferMemoryBarrier barrier; | 390 | [[nodiscard]] VkImageSubresourceLayers MakeSubresourceLayers(const ImageView* image_view) { |
| 284 | barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; | 391 | return VkImageSubresourceLayers{ |
| 285 | barrier.pNext = nullptr; | 392 | .aspectMask = ImageAspectMask(image_view->format), |
| 286 | barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | 393 | .mipLevel = static_cast<u32>(image_view->range.base.level), |
| 287 | barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | 394 | .baseArrayLayer = static_cast<u32>(image_view->range.base.layer), |
| 288 | barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // They'll be ignored anyway | 395 | .layerCount = static_cast<u32>(image_view->range.extent.layers), |
| 289 | barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | 396 | }; |
| 290 | barrier.buffer = dst_buffer; | ||
| 291 | barrier.offset = 0; | ||
| 292 | barrier.size = size; | ||
| 293 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, | ||
| 294 | 0, {}, barrier, {}); | ||
| 295 | }); | ||
| 296 | } | 397 | } |
| 297 | 398 | ||
| 298 | void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) { | 399 | [[nodiscard]] constexpr SwizzleSource ConvertGreenRed(SwizzleSource value) { |
| 299 | const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); | 400 | switch (value) { |
| 300 | std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); | 401 | case SwizzleSource::G: |
| 301 | 402 | return SwizzleSource::R; | |
| 302 | FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, | 403 | default: |
| 303 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 404 | return value; |
| 304 | |||
| 305 | for (u32 level = 0; level < params.num_levels; ++level) { | ||
| 306 | const VkBufferImageCopy copy = GetBufferImageCopy(level); | ||
| 307 | if (image->GetAspectMask() == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | ||
| 308 | scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(), | ||
| 309 | copy](vk::CommandBuffer cmdbuf) { | ||
| 310 | std::array<VkBufferImageCopy, 2> copies = {copy, copy}; | ||
| 311 | copies[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 312 | copies[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; | ||
| 313 | cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 314 | copies); | ||
| 315 | }); | ||
| 316 | } else { | ||
| 317 | scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(), | ||
| 318 | copy](vk::CommandBuffer cmdbuf) { | ||
| 319 | cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); | ||
| 320 | }); | ||
| 321 | } | ||
| 322 | } | 405 | } |
| 323 | } | 406 | } |
| 324 | 407 | ||
| 325 | VkBufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { | 408 | void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image, |
| 326 | return { | 409 | VkImageAspectFlags aspect_mask, bool is_initialized, |
| 327 | .bufferOffset = params.GetHostMipmapLevelOffset(level, is_converted), | 410 | std::span<const VkBufferImageCopy> copies) { |
| 328 | .bufferRowLength = 0, | 411 | static constexpr VkAccessFlags ACCESS_FLAGS = VK_ACCESS_SHADER_WRITE_BIT | |
| 329 | .bufferImageHeight = 0, | 412 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| 330 | .imageSubresource = | 413 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; |
| 414 | const VkImageMemoryBarrier read_barrier{ | ||
| 415 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 416 | .pNext = nullptr, | ||
| 417 | .srcAccessMask = ACCESS_FLAGS, | ||
| 418 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 419 | .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 420 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 421 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 422 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 423 | .image = image, | ||
| 424 | .subresourceRange = | ||
| 331 | { | 425 | { |
| 332 | .aspectMask = image->GetAspectMask(), | 426 | .aspectMask = aspect_mask, |
| 333 | .mipLevel = level, | 427 | .baseMipLevel = 0, |
| 428 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 334 | .baseArrayLayer = 0, | 429 | .baseArrayLayer = 0, |
| 335 | .layerCount = static_cast<u32>(params.GetNumLayers()), | 430 | .layerCount = VK_REMAINING_ARRAY_LAYERS, |
| 336 | }, | 431 | }, |
| 337 | .imageOffset = {.x = 0, .y = 0, .z = 0}, | 432 | }; |
| 338 | .imageExtent = | 433 | const VkImageMemoryBarrier write_barrier{ |
| 434 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 435 | .pNext = nullptr, | ||
| 436 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 437 | .dstAccessMask = ACCESS_FLAGS, | ||
| 438 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 439 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 440 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 441 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 442 | .image = image, | ||
| 443 | .subresourceRange = | ||
| 339 | { | 444 | { |
| 340 | .width = params.GetMipWidth(level), | 445 | .aspectMask = aspect_mask, |
| 341 | .height = params.GetMipHeight(level), | 446 | .baseMipLevel = 0, |
| 342 | .depth = params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1U, | 447 | .levelCount = VK_REMAINING_MIP_LEVELS, |
| 448 | .baseArrayLayer = 0, | ||
| 449 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 343 | }, | 450 | }, |
| 344 | }; | 451 | }; |
| 452 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, | ||
| 453 | read_barrier); | ||
| 454 | cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies); | ||
| 455 | // TODO: Move this to another API | ||
| 456 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, | ||
| 457 | write_barrier); | ||
| 345 | } | 458 | } |
| 346 | 459 | ||
| 347 | VkImageSubresourceRange CachedSurface::GetImageSubresourceRange() const { | 460 | [[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region, |
| 348 | return {image->GetAspectMask(), 0, params.num_levels, 0, | 461 | const std::array<Offset2D, 2>& src_region, |
| 349 | static_cast<u32>(params.GetNumLayers())}; | 462 | const VkImageSubresourceLayers& dst_layers, |
| 463 | const VkImageSubresourceLayers& src_layers) { | ||
| 464 | return VkImageBlit{ | ||
| 465 | .srcSubresource = src_layers, | ||
| 466 | .srcOffsets = | ||
| 467 | { | ||
| 468 | { | ||
| 469 | .x = src_region[0].x, | ||
| 470 | .y = src_region[0].y, | ||
| 471 | .z = 0, | ||
| 472 | }, | ||
| 473 | { | ||
| 474 | .x = src_region[1].x, | ||
| 475 | .y = src_region[1].y, | ||
| 476 | .z = 1, | ||
| 477 | }, | ||
| 478 | }, | ||
| 479 | .dstSubresource = dst_layers, | ||
| 480 | .dstOffsets = | ||
| 481 | { | ||
| 482 | { | ||
| 483 | .x = dst_region[0].x, | ||
| 484 | .y = dst_region[0].y, | ||
| 485 | .z = 0, | ||
| 486 | }, | ||
| 487 | { | ||
| 488 | .x = dst_region[1].x, | ||
| 489 | .y = dst_region[1].y, | ||
| 490 | .z = 1, | ||
| 491 | }, | ||
| 492 | }, | ||
| 493 | }; | ||
| 350 | } | 494 | } |
| 351 | 495 | ||
| 352 | CachedSurfaceView::CachedSurfaceView(const VKDevice& device_, CachedSurface& surface_, | 496 | [[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region, |
| 353 | const ViewParams& view_params_) | 497 | const std::array<Offset2D, 2>& src_region, |
| 354 | : ViewBase{view_params_}, surface_params{surface_.GetSurfaceParams()}, | 498 | const VkImageSubresourceLayers& dst_layers, |
| 355 | image{surface_.GetImageHandle()}, buffer_view{surface_.GetBufferViewHandle()}, | 499 | const VkImageSubresourceLayers& src_layers) { |
| 356 | aspect_mask{surface_.GetAspectMask()}, device{device_}, surface{surface_}, | 500 | return VkImageResolve{ |
| 357 | base_level{view_params_.base_level}, num_levels{view_params_.num_levels}, | 501 | .srcSubresource = src_layers, |
| 358 | image_view_type{image ? GetImageViewType(view_params_.target) : VK_IMAGE_VIEW_TYPE_1D} { | 502 | .srcOffset = |
| 359 | if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { | 503 | { |
| 360 | base_layer = 0; | 504 | .x = src_region[0].x, |
| 361 | num_layers = 1; | 505 | .y = src_region[0].y, |
| 362 | base_slice = view_params_.base_layer; | 506 | .z = 0, |
| 363 | num_slices = view_params_.num_layers; | 507 | }, |
| 364 | } else { | 508 | .dstSubresource = dst_layers, |
| 365 | base_layer = view_params_.base_layer; | 509 | .dstOffset = |
| 366 | num_layers = view_params_.num_layers; | 510 | { |
| 367 | } | 511 | .x = dst_region[0].x, |
| 512 | .y = dst_region[0].y, | ||
| 513 | .z = 0, | ||
| 514 | }, | ||
| 515 | .extent = | ||
| 516 | { | ||
| 517 | .width = static_cast<u32>(dst_region[1].x - dst_region[0].x), | ||
| 518 | .height = static_cast<u32>(dst_region[1].y - dst_region[0].y), | ||
| 519 | .depth = 1, | ||
| 520 | }, | ||
| 521 | }; | ||
| 368 | } | 522 | } |
| 369 | 523 | ||
| 370 | CachedSurfaceView::~CachedSurfaceView() = default; | 524 | struct RangedBarrierRange { |
| 371 | 525 | u32 min_mip = std::numeric_limits<u32>::max(); | |
| 372 | VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSource y_source, | 526 | u32 max_mip = std::numeric_limits<u32>::min(); |
| 373 | SwizzleSource z_source, SwizzleSource w_source) { | 527 | u32 min_layer = std::numeric_limits<u32>::max(); |
| 374 | const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); | 528 | u32 max_layer = std::numeric_limits<u32>::min(); |
| 375 | if (last_image_view && last_swizzle == new_swizzle) { | 529 | |
| 376 | return last_image_view; | 530 | void AddLayers(const VkImageSubresourceLayers& layers) { |
| 531 | min_mip = std::min(min_mip, layers.mipLevel); | ||
| 532 | max_mip = std::max(max_mip, layers.mipLevel + 1); | ||
| 533 | min_layer = std::min(min_layer, layers.baseArrayLayer); | ||
| 534 | max_layer = std::max(max_layer, layers.baseArrayLayer + layers.layerCount); | ||
| 377 | } | 535 | } |
| 378 | last_swizzle = new_swizzle; | ||
| 379 | 536 | ||
| 380 | const auto [entry, is_cache_miss] = view_cache.try_emplace(new_swizzle); | 537 | VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) const noexcept { |
| 381 | auto& image_view = entry->second; | 538 | return VkImageSubresourceRange{ |
| 382 | if (!is_cache_miss) { | 539 | .aspectMask = aspect_mask, |
| 383 | return last_image_view = *image_view; | 540 | .baseMipLevel = min_mip, |
| 541 | .levelCount = max_mip - min_mip, | ||
| 542 | .baseArrayLayer = min_layer, | ||
| 543 | .layerCount = max_layer - min_layer, | ||
| 544 | }; | ||
| 384 | } | 545 | } |
| 546 | }; | ||
| 385 | 547 | ||
| 386 | std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source), | 548 | } // Anonymous namespace |
| 387 | MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)}; | ||
| 388 | if (surface_params.pixel_format == PixelFormat::A1B5G5R5_UNORM) { | ||
| 389 | // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here. | ||
| 390 | std::swap(swizzle[0], swizzle[2]); | ||
| 391 | } | ||
| 392 | 549 | ||
| 393 | // Games can sample depth or stencil values on textures. This is decided by the swizzle value on | 550 | void TextureCacheRuntime::Finish() { |
| 394 | // hardware. To emulate this on Vulkan we specify it in the aspect. | 551 | scheduler.Finish(); |
| 395 | VkImageAspectFlags aspect = aspect_mask; | 552 | } |
| 396 | if (aspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | ||
| 397 | UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G); | ||
| 398 | const bool is_first = x_source == SwizzleSource::R; | ||
| 399 | switch (surface_params.pixel_format) { | ||
| 400 | case PixelFormat::D24_UNORM_S8_UINT: | ||
| 401 | case PixelFormat::D32_FLOAT_S8_UINT: | ||
| 402 | aspect = is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT; | ||
| 403 | break; | ||
| 404 | case PixelFormat::S8_UINT_D24_UNORM: | ||
| 405 | aspect = is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 406 | break; | ||
| 407 | default: | ||
| 408 | aspect = VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 409 | UNIMPLEMENTED(); | ||
| 410 | } | ||
| 411 | 553 | ||
| 412 | // Make sure we sample the first component | 554 | ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { |
| 413 | std::transform( | 555 | const auto& buffer = staging_buffer_pool.GetUnusedBuffer(size, true); |
| 414 | swizzle.begin(), swizzle.end(), swizzle.begin(), [](VkComponentSwizzle component) { | 556 | return ImageBufferMap{ |
| 415 | return component == VK_COMPONENT_SWIZZLE_G ? VK_COMPONENT_SWIZZLE_R : component; | 557 | .handle = *buffer.handle, |
| 416 | }); | 558 | .map = buffer.commit->Map(size), |
| 417 | } | 559 | }; |
| 560 | } | ||
| 418 | 561 | ||
| 419 | if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { | 562 | void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 420 | ASSERT(base_slice == 0); | 563 | const std::array<Offset2D, 2>& dst_region, |
| 421 | ASSERT(num_slices == surface_params.depth); | 564 | const std::array<Offset2D, 2>& src_region, |
| 565 | Tegra::Engines::Fermi2D::Filter filter, | ||
| 566 | Tegra::Engines::Fermi2D::Operation operation) { | ||
| 567 | const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format); | ||
| 568 | const bool is_dst_msaa = dst.Samples() != VK_SAMPLE_COUNT_1_BIT; | ||
| 569 | const bool is_src_msaa = src.Samples() != VK_SAMPLE_COUNT_1_BIT; | ||
| 570 | ASSERT(aspect_mask == ImageAspectMask(dst.format)); | ||
| 571 | if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) { | ||
| 572 | blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, filter, | ||
| 573 | operation); | ||
| 574 | return; | ||
| 422 | } | 575 | } |
| 423 | 576 | if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | |
| 424 | image_view = device.GetLogical().CreateImageView({ | 577 | if (!device.IsBlitDepthStencilSupported()) { |
| 425 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 578 | UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa); |
| 426 | .pNext = nullptr, | 579 | blit_image_helper.BlitDepthStencil(dst_framebuffer, src.DepthView(), src.StencilView(), |
| 427 | .flags = 0, | 580 | dst_region, src_region, filter, operation); |
| 428 | .image = surface.GetImageHandle(), | 581 | return; |
| 429 | .viewType = image_view_type, | 582 | } |
| 430 | .format = surface.GetImage().GetFormat(), | 583 | } |
| 431 | .components = | 584 | ASSERT(src.ImageFormat() == dst.ImageFormat()); |
| 432 | { | 585 | ASSERT(!(is_dst_msaa && !is_src_msaa)); |
| 433 | .r = swizzle[0], | 586 | ASSERT(operation == Fermi2D::Operation::SrcCopy); |
| 434 | .g = swizzle[1], | 587 | |
| 435 | .b = swizzle[2], | 588 | const VkImage dst_image = dst.ImageHandle(); |
| 436 | .a = swizzle[3], | 589 | const VkImage src_image = src.ImageHandle(); |
| 590 | const VkImageSubresourceLayers dst_layers = MakeSubresourceLayers(&dst); | ||
| 591 | const VkImageSubresourceLayers src_layers = MakeSubresourceLayers(&src); | ||
| 592 | const bool is_resolve = is_src_msaa && !is_dst_msaa; | ||
| 593 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 594 | scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers, | ||
| 595 | aspect_mask, is_resolve](vk::CommandBuffer cmdbuf) { | ||
| 596 | const std::array read_barriers{ | ||
| 597 | VkImageMemoryBarrier{ | ||
| 598 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 599 | .pNext = nullptr, | ||
| 600 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | | ||
| 601 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 602 | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 603 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 604 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 605 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 606 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 607 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 608 | .image = src_image, | ||
| 609 | .subresourceRange{ | ||
| 610 | .aspectMask = aspect_mask, | ||
| 611 | .baseMipLevel = 0, | ||
| 612 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 613 | .baseArrayLayer = 0, | ||
| 614 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 615 | }, | ||
| 437 | }, | 616 | }, |
| 438 | .subresourceRange = | 617 | VkImageMemoryBarrier{ |
| 439 | { | 618 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| 440 | .aspectMask = aspect, | 619 | .pNext = nullptr, |
| 441 | .baseMipLevel = base_level, | 620 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | |
| 442 | .levelCount = num_levels, | 621 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | |
| 443 | .baseArrayLayer = base_layer, | 622 | VK_ACCESS_TRANSFER_WRITE_BIT, |
| 444 | .layerCount = num_layers, | 623 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 624 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 625 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 626 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 627 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 628 | .image = dst_image, | ||
| 629 | .subresourceRange{ | ||
| 630 | .aspectMask = aspect_mask, | ||
| 631 | .baseMipLevel = 0, | ||
| 632 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 633 | .baseArrayLayer = 0, | ||
| 634 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 635 | }, | ||
| 636 | }, | ||
| 637 | }; | ||
| 638 | VkImageMemoryBarrier write_barrier{ | ||
| 639 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 640 | .pNext = nullptr, | ||
| 641 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 642 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | | ||
| 643 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 644 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 645 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 646 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 647 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 648 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 649 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 650 | .image = dst_image, | ||
| 651 | .subresourceRange{ | ||
| 652 | .aspectMask = aspect_mask, | ||
| 653 | .baseMipLevel = 0, | ||
| 654 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 655 | .baseArrayLayer = 0, | ||
| 656 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 445 | }, | 657 | }, |
| 658 | }; | ||
| 659 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 660 | 0, nullptr, nullptr, read_barriers); | ||
| 661 | if (is_resolve) { | ||
| 662 | cmdbuf.ResolveImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, | ||
| 663 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 664 | MakeImageResolve(dst_region, src_region, dst_layers, src_layers)); | ||
| 665 | } else { | ||
| 666 | const bool is_linear = filter == Fermi2D::Filter::Bilinear; | ||
| 667 | const VkFilter vk_filter = is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; | ||
| 668 | cmdbuf.BlitImage( | ||
| 669 | src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 670 | MakeImageBlit(dst_region, src_region, dst_layers, src_layers), vk_filter); | ||
| 671 | } | ||
| 672 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 673 | 0, write_barrier); | ||
| 446 | }); | 674 | }); |
| 447 | |||
| 448 | return last_image_view = *image_view; | ||
| 449 | } | 675 | } |
| 450 | 676 | ||
| 451 | VkImageView CachedSurfaceView::GetAttachment() { | 677 | void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) { |
| 452 | if (render_target) { | 678 | switch (dst_view.format) { |
| 453 | return *render_target; | 679 | case PixelFormat::R16_UNORM: |
| 680 | if (src_view.format == PixelFormat::D16_UNORM) { | ||
| 681 | return blit_image_helper.ConvertD16ToR16(dst, src_view); | ||
| 682 | } | ||
| 683 | break; | ||
| 684 | case PixelFormat::R32_FLOAT: | ||
| 685 | if (src_view.format == PixelFormat::D32_FLOAT) { | ||
| 686 | return blit_image_helper.ConvertD32ToR32(dst, src_view); | ||
| 687 | } | ||
| 688 | break; | ||
| 689 | case PixelFormat::D16_UNORM: | ||
| 690 | if (src_view.format == PixelFormat::R16_UNORM) { | ||
| 691 | return blit_image_helper.ConvertR16ToD16(dst, src_view); | ||
| 692 | } | ||
| 693 | break; | ||
| 694 | case PixelFormat::D32_FLOAT: | ||
| 695 | if (src_view.format == PixelFormat::R32_FLOAT) { | ||
| 696 | return blit_image_helper.ConvertR32ToD32(dst, src_view); | ||
| 697 | } | ||
| 698 | break; | ||
| 699 | default: | ||
| 700 | break; | ||
| 454 | } | 701 | } |
| 702 | UNIMPLEMENTED_MSG("Unimplemented format copy from {} to {}", src_view.format, dst_view.format); | ||
| 703 | } | ||
| 455 | 704 | ||
| 456 | VkImageViewCreateInfo ci{ | 705 | void TextureCacheRuntime::CopyImage(Image& dst, Image& src, |
| 457 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 706 | std::span<const VideoCommon::ImageCopy> copies) { |
| 458 | .pNext = nullptr, | 707 | std::vector<VkImageCopy> vk_copies(copies.size()); |
| 459 | .flags = 0, | 708 | const VkImageAspectFlags aspect_mask = dst.AspectMask(); |
| 460 | .image = surface.GetImageHandle(), | 709 | ASSERT(aspect_mask == src.AspectMask()); |
| 461 | .viewType = VK_IMAGE_VIEW_TYPE_1D, | 710 | |
| 462 | .format = surface.GetImage().GetFormat(), | 711 | std::ranges::transform(copies, vk_copies.begin(), [aspect_mask](const auto& copy) { |
| 463 | .components = | 712 | return MakeImageCopy(copy, aspect_mask); |
| 464 | { | 713 | }); |
| 465 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | 714 | const VkImage dst_image = dst.Handle(); |
| 466 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | 715 | const VkImage src_image = src.Handle(); |
| 467 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | 716 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 468 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | 717 | scheduler.Record([dst_image, src_image, aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { |
| 718 | RangedBarrierRange dst_range; | ||
| 719 | RangedBarrierRange src_range; | ||
| 720 | for (const VkImageCopy& copy : vk_copies) { | ||
| 721 | dst_range.AddLayers(copy.dstSubresource); | ||
| 722 | src_range.AddLayers(copy.srcSubresource); | ||
| 723 | } | ||
| 724 | const std::array read_barriers{ | ||
| 725 | VkImageMemoryBarrier{ | ||
| 726 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 727 | .pNext = nullptr, | ||
| 728 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 729 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 730 | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 731 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 732 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 733 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 734 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 735 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 736 | .image = src_image, | ||
| 737 | .subresourceRange = src_range.SubresourceRange(aspect_mask), | ||
| 469 | }, | 738 | }, |
| 470 | .subresourceRange = | 739 | VkImageMemoryBarrier{ |
| 471 | { | 740 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| 472 | .aspectMask = aspect_mask, | 741 | .pNext = nullptr, |
| 473 | .baseMipLevel = base_level, | 742 | .srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | |
| 474 | .levelCount = num_levels, | 743 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
| 475 | .baseArrayLayer = 0, | 744 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| 476 | .layerCount = 0, | 745 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
| 746 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 747 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 748 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 749 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 750 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 751 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 752 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 753 | .image = dst_image, | ||
| 754 | .subresourceRange = dst_range.SubresourceRange(aspect_mask), | ||
| 477 | }, | 755 | }, |
| 478 | }; | 756 | }; |
| 479 | if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { | 757 | const VkImageMemoryBarrier write_barrier{ |
| 480 | ci.viewType = num_slices > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; | 758 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| 481 | ci.subresourceRange.baseArrayLayer = base_slice; | 759 | .pNext = nullptr, |
| 482 | ci.subresourceRange.layerCount = num_slices; | 760 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 761 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | | ||
| 762 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | | ||
| 763 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 764 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 765 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 766 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 767 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 768 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 769 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 770 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 771 | .image = dst_image, | ||
| 772 | .subresourceRange = dst_range.SubresourceRange(aspect_mask), | ||
| 773 | }; | ||
| 774 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 775 | 0, {}, {}, read_barriers); | ||
| 776 | cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, | ||
| 777 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_copies); | ||
| 778 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 779 | 0, write_barrier); | ||
| 780 | }); | ||
| 781 | } | ||
| 782 | |||
| 783 | Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_addr_, | ||
| 784 | VAddr cpu_addr_) | ||
| 785 | : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime.scheduler}, | ||
| 786 | image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), | ||
| 787 | aspect_mask(ImageAspectMask(info.format)) { | ||
| 788 | if (image) { | ||
| 789 | commit = runtime.memory_manager.Commit(image, false); | ||
| 483 | } else { | 790 | } else { |
| 484 | ci.viewType = image_view_type; | 791 | commit = runtime.memory_manager.Commit(buffer, false); |
| 485 | ci.subresourceRange.baseArrayLayer = base_layer; | 792 | } |
| 486 | ci.subresourceRange.layerCount = num_layers; | 793 | if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { |
| 794 | flags |= VideoCommon::ImageFlagBits::Converted; | ||
| 795 | } | ||
| 796 | if (runtime.device.HasDebuggingToolAttached()) { | ||
| 797 | if (image) { | ||
| 798 | image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); | ||
| 799 | } else { | ||
| 800 | buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); | ||
| 801 | } | ||
| 487 | } | 802 | } |
| 488 | render_target = device.GetLogical().CreateImageView(ci); | ||
| 489 | return *render_target; | ||
| 490 | } | 803 | } |
| 491 | 804 | ||
| 492 | VKTextureCache::VKTextureCache(VideoCore::RasterizerInterface& rasterizer_, | 805 | void Image::UploadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 493 | Tegra::Engines::Maxwell3D& maxwell3d_, | 806 | std::span<const BufferImageCopy> copies) { |
| 494 | Tegra::MemoryManager& gpu_memory_, const VKDevice& device_, | 807 | // TODO: Move this to another API |
| 495 | VKMemoryManager& memory_manager_, VKScheduler& scheduler_, | 808 | scheduler->RequestOutsideRenderPassOperationContext(); |
| 496 | VKStagingBufferPool& staging_pool_) | 809 | std::vector vk_copies = TransformBufferImageCopies(copies, buffer_offset, aspect_mask); |
| 497 | : TextureCache(rasterizer_, maxwell3d_, gpu_memory_, device_.IsOptimalAstcSupported()), | 810 | const VkBuffer src_buffer = map.handle; |
| 498 | device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ | 811 | const VkImage vk_image = *image; |
| 499 | staging_pool_} {} | 812 | const VkImageAspectFlags vk_aspect_mask = aspect_mask; |
| 500 | 813 | const bool is_initialized = std::exchange(initialized, true); | |
| 501 | VKTextureCache::~VKTextureCache() = default; | 814 | scheduler->Record([src_buffer, vk_image, vk_aspect_mask, is_initialized, |
| 502 | 815 | vk_copies](vk::CommandBuffer cmdbuf) { | |
| 503 | Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { | 816 | CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, is_initialized, vk_copies); |
| 504 | return std::make_shared<CachedSurface>(device, memory_manager, scheduler, staging_pool, | 817 | }); |
| 505 | gpu_addr, params); | ||
| 506 | } | 818 | } |
| 507 | 819 | ||
| 508 | void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface, | 820 | void Image::UploadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 509 | const VideoCommon::CopyParams& copy_params) { | 821 | std::span<const VideoCommon::BufferCopy> copies) { |
| 510 | const bool src_3d = src_surface->GetSurfaceParams().target == SurfaceTarget::Texture3D; | 822 | // TODO: Move this to another API |
| 511 | const bool dst_3d = dst_surface->GetSurfaceParams().target == SurfaceTarget::Texture3D; | 823 | scheduler->RequestOutsideRenderPassOperationContext(); |
| 512 | UNIMPLEMENTED_IF(src_3d); | 824 | std::vector vk_copies = TransformBufferCopies(copies, buffer_offset); |
| 825 | const VkBuffer src_buffer = map.handle; | ||
| 826 | const VkBuffer dst_buffer = *buffer; | ||
| 827 | scheduler->Record([src_buffer, dst_buffer, vk_copies](vk::CommandBuffer cmdbuf) { | ||
| 828 | // TODO: Barriers | ||
| 829 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, vk_copies); | ||
| 830 | }); | ||
| 831 | } | ||
| 513 | 832 | ||
| 514 | // The texture cache handles depth in OpenGL terms, we have to handle it as subresource and | 833 | void Image::DownloadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 515 | // dimension respectively. | 834 | std::span<const BufferImageCopy> copies) { |
| 516 | const u32 dst_base_layer = dst_3d ? 0 : copy_params.dest_z; | 835 | std::vector vk_copies = TransformBufferImageCopies(copies, buffer_offset, aspect_mask); |
| 517 | const u32 dst_offset_z = dst_3d ? copy_params.dest_z : 0; | 836 | scheduler->Record([buffer = map.handle, image = *image, aspect_mask = aspect_mask, |
| 837 | vk_copies](vk::CommandBuffer cmdbuf) { | ||
| 838 | // TODO: Barriers | ||
| 839 | cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_GENERAL, buffer, vk_copies); | ||
| 840 | }); | ||
| 841 | } | ||
| 518 | 842 | ||
| 519 | const u32 extent_z = dst_3d ? copy_params.depth : 1; | 843 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, |
| 520 | const u32 num_layers = dst_3d ? 1 : copy_params.depth; | 844 | ImageId image_id_, Image& image) |
| 845 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device}, | ||
| 846 | image_handle{image.Handle()}, image_format{image.info.format}, samples{ConvertSampleCount( | ||
| 847 | image.info.num_samples)} { | ||
| 848 | const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); | ||
| 849 | std::array<SwizzleSource, 4> swizzle{ | ||
| 850 | SwizzleSource::R, | ||
| 851 | SwizzleSource::G, | ||
| 852 | SwizzleSource::B, | ||
| 853 | SwizzleSource::A, | ||
| 854 | }; | ||
| 855 | if (!info.IsRenderTarget()) { | ||
| 856 | swizzle = info.Swizzle(); | ||
| 857 | if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { | ||
| 858 | std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); | ||
| 859 | } | ||
| 860 | } | ||
| 861 | const VkFormat vk_format = | ||
| 862 | MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format; | ||
| 863 | const VkImageViewCreateInfo create_info{ | ||
| 864 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 865 | .pNext = nullptr, | ||
| 866 | .flags = 0, | ||
| 867 | .image = image.Handle(), | ||
| 868 | .viewType = VkImageViewType{}, | ||
| 869 | .format = vk_format, | ||
| 870 | .components{ | ||
| 871 | .r = ComponentSwizzle(swizzle[0]), | ||
| 872 | .g = ComponentSwizzle(swizzle[1]), | ||
| 873 | .b = ComponentSwizzle(swizzle[2]), | ||
| 874 | .a = ComponentSwizzle(swizzle[3]), | ||
| 875 | }, | ||
| 876 | .subresourceRange = MakeSubresourceRange(aspect_mask, info.range), | ||
| 877 | }; | ||
| 878 | const auto create = [&](VideoCommon::ImageViewType view_type, std::optional<u32> num_layers) { | ||
| 879 | VkImageViewCreateInfo ci{create_info}; | ||
| 880 | ci.viewType = ImageViewType(view_type); | ||
| 881 | if (num_layers) { | ||
| 882 | ci.subresourceRange.layerCount = *num_layers; | ||
| 883 | } | ||
| 884 | vk::ImageView handle = device->GetLogical().CreateImageView(ci); | ||
| 885 | if (device->HasDebuggingToolAttached()) { | ||
| 886 | handle.SetObjectNameEXT(VideoCommon::Name(*this, view_type).c_str()); | ||
| 887 | } | ||
| 888 | image_views[static_cast<size_t>(view_type)] = std::move(handle); | ||
| 889 | }; | ||
| 890 | switch (info.type) { | ||
| 891 | case VideoCommon::ImageViewType::e1D: | ||
| 892 | case VideoCommon::ImageViewType::e1DArray: | ||
| 893 | create(VideoCommon::ImageViewType::e1D, 1); | ||
| 894 | create(VideoCommon::ImageViewType::e1DArray, std::nullopt); | ||
| 895 | render_target = Handle(VideoCommon::ImageViewType::e1DArray); | ||
| 896 | break; | ||
| 897 | case VideoCommon::ImageViewType::e2D: | ||
| 898 | case VideoCommon::ImageViewType::e2DArray: | ||
| 899 | create(VideoCommon::ImageViewType::e2D, 1); | ||
| 900 | create(VideoCommon::ImageViewType::e2DArray, std::nullopt); | ||
| 901 | render_target = Handle(VideoCommon::ImageViewType::e2DArray); | ||
| 902 | break; | ||
| 903 | case VideoCommon::ImageViewType::e3D: | ||
| 904 | create(VideoCommon::ImageViewType::e3D, std::nullopt); | ||
| 905 | render_target = Handle(VideoCommon::ImageViewType::e3D); | ||
| 906 | break; | ||
| 907 | case VideoCommon::ImageViewType::Cube: | ||
| 908 | case VideoCommon::ImageViewType::CubeArray: | ||
| 909 | create(VideoCommon::ImageViewType::Cube, 6); | ||
| 910 | create(VideoCommon::ImageViewType::CubeArray, std::nullopt); | ||
| 911 | break; | ||
| 912 | case VideoCommon::ImageViewType::Rect: | ||
| 913 | UNIMPLEMENTED(); | ||
| 914 | break; | ||
| 915 | case VideoCommon::ImageViewType::Buffer: | ||
| 916 | buffer_view = device->GetLogical().CreateBufferView(VkBufferViewCreateInfo{ | ||
| 917 | .sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, | ||
| 918 | .pNext = nullptr, | ||
| 919 | .flags = 0, | ||
| 920 | .buffer = image.Buffer(), | ||
| 921 | .format = vk_format, | ||
| 922 | .offset = 0, // TODO: Redesign buffer cache to support this | ||
| 923 | .range = image.guest_size_bytes, | ||
| 924 | }); | ||
| 925 | break; | ||
| 926 | } | ||
| 927 | } | ||
| 521 | 928 | ||
| 522 | // We can't copy inside a renderpass | 929 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams& params) |
| 523 | scheduler.RequestOutsideRenderPassOperationContext(); | 930 | : VideoCommon::ImageViewBase{params} {} |
| 524 | 931 | ||
| 525 | src_surface->Transition(copy_params.source_z, copy_params.depth, copy_params.source_level, 1, | 932 | VkImageView ImageView::DepthView() { |
| 526 | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, | 933 | if (depth_view) { |
| 527 | VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); | 934 | return *depth_view; |
| 528 | dst_surface->Transition(dst_base_layer, num_layers, copy_params.dest_level, 1, | 935 | } |
| 529 | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, | 936 | depth_view = MakeDepthStencilView(VK_IMAGE_ASPECT_DEPTH_BIT); |
| 530 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 937 | return *depth_view; |
| 938 | } | ||
| 531 | 939 | ||
| 532 | const VkImageCopy copy{ | 940 | VkImageView ImageView::StencilView() { |
| 533 | .srcSubresource = | 941 | if (stencil_view) { |
| 534 | { | 942 | return *stencil_view; |
| 535 | .aspectMask = src_surface->GetAspectMask(), | 943 | } |
| 536 | .mipLevel = copy_params.source_level, | 944 | stencil_view = MakeDepthStencilView(VK_IMAGE_ASPECT_STENCIL_BIT); |
| 537 | .baseArrayLayer = copy_params.source_z, | 945 | return *stencil_view; |
| 538 | .layerCount = num_layers, | 946 | } |
| 539 | }, | ||
| 540 | .srcOffset = | ||
| 541 | { | ||
| 542 | .x = static_cast<s32>(copy_params.source_x), | ||
| 543 | .y = static_cast<s32>(copy_params.source_y), | ||
| 544 | .z = 0, | ||
| 545 | }, | ||
| 546 | .dstSubresource = | ||
| 547 | { | ||
| 548 | .aspectMask = dst_surface->GetAspectMask(), | ||
| 549 | .mipLevel = copy_params.dest_level, | ||
| 550 | .baseArrayLayer = dst_base_layer, | ||
| 551 | .layerCount = num_layers, | ||
| 552 | }, | ||
| 553 | .dstOffset = | ||
| 554 | { | ||
| 555 | .x = static_cast<s32>(copy_params.dest_x), | ||
| 556 | .y = static_cast<s32>(copy_params.dest_y), | ||
| 557 | .z = static_cast<s32>(dst_offset_z), | ||
| 558 | }, | ||
| 559 | .extent = | ||
| 560 | { | ||
| 561 | .width = copy_params.width, | ||
| 562 | .height = copy_params.height, | ||
| 563 | .depth = extent_z, | ||
| 564 | }, | ||
| 565 | }; | ||
| 566 | 947 | ||
| 567 | const VkImage src_image = src_surface->GetImageHandle(); | 948 | vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) { |
| 568 | const VkImage dst_image = dst_surface->GetImageHandle(); | 949 | return device->GetLogical().CreateImageView({ |
| 569 | scheduler.Record([src_image, dst_image, copy](vk::CommandBuffer cmdbuf) { | 950 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 570 | cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, | 951 | .pNext = nullptr, |
| 571 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); | 952 | .flags = 0, |
| 953 | .image = image_handle, | ||
| 954 | .viewType = ImageViewType(type), | ||
| 955 | .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format, | ||
| 956 | .components{ | ||
| 957 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 958 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 959 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 960 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 961 | }, | ||
| 962 | .subresourceRange = MakeSubresourceRange(aspect_mask, range), | ||
| 572 | }); | 963 | }); |
| 573 | } | 964 | } |
| 574 | 965 | ||
| 575 | void VKTextureCache::ImageBlit(View& src_view, View& dst_view, | 966 | Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) { |
| 576 | const Tegra::Engines::Fermi2D::Config& copy_config) { | 967 | const auto& device = runtime.device; |
| 577 | // We can't blit inside a renderpass | 968 | const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported(); |
| 578 | scheduler.RequestOutsideRenderPassOperationContext(); | 969 | const std::array<float, 4> color = tsc.BorderColor(); |
| 579 | 970 | // C++20 bit_cast | |
| 580 | src_view->Transition(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, | 971 | VkClearColorValue border_color; |
| 581 | VK_ACCESS_TRANSFER_READ_BIT); | 972 | std::memcpy(&border_color, &color, sizeof(color)); |
| 582 | dst_view->Transition(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, | 973 | const VkSamplerCustomBorderColorCreateInfoEXT border_ci{ |
| 583 | VK_ACCESS_TRANSFER_WRITE_BIT); | 974 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT, |
| 584 | 975 | .pNext = nullptr, | |
| 585 | VkImageBlit blit; | 976 | .customBorderColor = border_color, |
| 586 | blit.srcSubresource = src_view->GetImageSubresourceLayers(); | 977 | .format = VK_FORMAT_UNDEFINED, |
| 587 | blit.srcOffsets[0].x = copy_config.src_rect.left; | 978 | }; |
| 588 | blit.srcOffsets[0].y = copy_config.src_rect.top; | 979 | const void* pnext = nullptr; |
| 589 | blit.srcOffsets[0].z = 0; | 980 | if (arbitrary_borders) { |
| 590 | blit.srcOffsets[1].x = copy_config.src_rect.right; | 981 | pnext = &border_ci; |
| 591 | blit.srcOffsets[1].y = copy_config.src_rect.bottom; | 982 | } |
| 592 | blit.srcOffsets[1].z = 1; | 983 | const VkSamplerReductionModeCreateInfoEXT reduction_ci{ |
| 593 | blit.dstSubresource = dst_view->GetImageSubresourceLayers(); | 984 | .sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT, |
| 594 | blit.dstOffsets[0].x = copy_config.dst_rect.left; | 985 | .pNext = pnext, |
| 595 | blit.dstOffsets[0].y = copy_config.dst_rect.top; | 986 | .reductionMode = MaxwellToVK::SamplerReduction(tsc.reduction_filter), |
| 596 | blit.dstOffsets[0].z = 0; | 987 | }; |
| 597 | blit.dstOffsets[1].x = copy_config.dst_rect.right; | 988 | if (runtime.device.IsExtSamplerFilterMinmaxSupported()) { |
| 598 | blit.dstOffsets[1].y = copy_config.dst_rect.bottom; | 989 | pnext = &reduction_ci; |
| 599 | blit.dstOffsets[1].z = 1; | 990 | } else if (reduction_ci.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT) { |
| 600 | 991 | LOG_WARNING(Render_Vulkan, "VK_EXT_sampler_filter_minmax is required"); | |
| 601 | const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear; | 992 | } |
| 602 | 993 | // Some games have samplers with garbage. Sanitize them here. | |
| 603 | scheduler.Record([src_image = src_view->GetImage(), dst_image = dst_view->GetImage(), blit, | 994 | const float max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f); |
| 604 | is_linear](vk::CommandBuffer cmdbuf) { | 995 | sampler = device.GetLogical().CreateSampler(VkSamplerCreateInfo{ |
| 605 | cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, | 996 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, |
| 606 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, blit, | 997 | .pNext = pnext, |
| 607 | is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); | 998 | .flags = 0, |
| 999 | .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter), | ||
| 1000 | .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter), | ||
| 1001 | .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter), | ||
| 1002 | .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter), | ||
| 1003 | .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter), | ||
| 1004 | .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter), | ||
| 1005 | .mipLodBias = tsc.LodBias(), | ||
| 1006 | .anisotropyEnable = static_cast<VkBool32>(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE), | ||
| 1007 | .maxAnisotropy = max_anisotropy, | ||
| 1008 | .compareEnable = tsc.depth_compare_enabled, | ||
| 1009 | .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), | ||
| 1010 | .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), | ||
| 1011 | .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(), | ||
| 1012 | .borderColor = | ||
| 1013 | arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color), | ||
| 1014 | .unnormalizedCoordinates = VK_FALSE, | ||
| 608 | }); | 1015 | }); |
| 609 | } | 1016 | } |
| 610 | 1017 | ||
| 611 | void VKTextureCache::BufferCopy(Surface& src_surface, Surface& dst_surface) { | 1018 | Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers, |
| 612 | // Currently unimplemented. PBO copies should be dropped and we should use a render pass to | 1019 | ImageView* depth_buffer, const VideoCommon::RenderTargets& key) { |
| 613 | // convert from color to depth and viceversa. | 1020 | std::vector<VkAttachmentDescription> descriptions; |
| 614 | LOG_WARNING(Render_Vulkan, "Unimplemented"); | 1021 | std::vector<VkImageView> attachments; |
| 1022 | RenderPassKey renderpass_key{}; | ||
| 1023 | s32 num_layers = 1; | ||
| 1024 | |||
| 1025 | for (size_t index = 0; index < NUM_RT; ++index) { | ||
| 1026 | const ImageView* const color_buffer = color_buffers[index]; | ||
| 1027 | if (!color_buffer) { | ||
| 1028 | renderpass_key.color_formats[index] = PixelFormat::Invalid; | ||
| 1029 | continue; | ||
| 1030 | } | ||
| 1031 | descriptions.push_back(AttachmentDescription(runtime.device, color_buffer)); | ||
| 1032 | attachments.push_back(color_buffer->RenderTarget()); | ||
| 1033 | renderpass_key.color_formats[index] = color_buffer->format; | ||
| 1034 | num_layers = std::max(num_layers, color_buffer->range.extent.layers); | ||
| 1035 | images[num_images] = color_buffer->ImageHandle(); | ||
| 1036 | image_ranges[num_images] = MakeSubresourceRange(color_buffer); | ||
| 1037 | samples = color_buffer->Samples(); | ||
| 1038 | ++num_images; | ||
| 1039 | } | ||
| 1040 | const size_t num_colors = attachments.size(); | ||
| 1041 | const VkAttachmentReference* depth_attachment = | ||
| 1042 | depth_buffer ? &ATTACHMENT_REFERENCES[num_colors] : nullptr; | ||
| 1043 | if (depth_buffer) { | ||
| 1044 | descriptions.push_back(AttachmentDescription(runtime.device, depth_buffer)); | ||
| 1045 | attachments.push_back(depth_buffer->RenderTarget()); | ||
| 1046 | renderpass_key.depth_format = depth_buffer->format; | ||
| 1047 | num_layers = std::max(num_layers, depth_buffer->range.extent.layers); | ||
| 1048 | images[num_images] = depth_buffer->ImageHandle(); | ||
| 1049 | image_ranges[num_images] = MakeSubresourceRange(depth_buffer); | ||
| 1050 | samples = depth_buffer->Samples(); | ||
| 1051 | ++num_images; | ||
| 1052 | } else { | ||
| 1053 | renderpass_key.depth_format = PixelFormat::Invalid; | ||
| 1054 | } | ||
| 1055 | renderpass_key.samples = samples; | ||
| 1056 | |||
| 1057 | const auto& device = runtime.device.GetLogical(); | ||
| 1058 | const auto [cache_pair, is_new] = runtime.renderpass_cache.try_emplace(renderpass_key); | ||
| 1059 | if (is_new) { | ||
| 1060 | const VkSubpassDescription subpass{ | ||
| 1061 | .flags = 0, | ||
| 1062 | .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 1063 | .inputAttachmentCount = 0, | ||
| 1064 | .pInputAttachments = nullptr, | ||
| 1065 | .colorAttachmentCount = static_cast<u32>(num_colors), | ||
| 1066 | .pColorAttachments = num_colors != 0 ? ATTACHMENT_REFERENCES.data() : nullptr, | ||
| 1067 | .pResolveAttachments = nullptr, | ||
| 1068 | .pDepthStencilAttachment = depth_attachment, | ||
| 1069 | .preserveAttachmentCount = 0, | ||
| 1070 | .pPreserveAttachments = nullptr, | ||
| 1071 | }; | ||
| 1072 | cache_pair->second = device.CreateRenderPass(VkRenderPassCreateInfo{ | ||
| 1073 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | ||
| 1074 | .pNext = nullptr, | ||
| 1075 | .flags = 0, | ||
| 1076 | .attachmentCount = static_cast<u32>(descriptions.size()), | ||
| 1077 | .pAttachments = descriptions.data(), | ||
| 1078 | .subpassCount = 1, | ||
| 1079 | .pSubpasses = &subpass, | ||
| 1080 | .dependencyCount = 0, | ||
| 1081 | .pDependencies = nullptr, | ||
| 1082 | }); | ||
| 1083 | } | ||
| 1084 | renderpass = *cache_pair->second; | ||
| 1085 | render_area = VkExtent2D{ | ||
| 1086 | .width = key.size.width, | ||
| 1087 | .height = key.size.height, | ||
| 1088 | }; | ||
| 1089 | num_color_buffers = static_cast<u32>(num_colors); | ||
| 1090 | framebuffer = device.CreateFramebuffer(VkFramebufferCreateInfo{ | ||
| 1091 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | ||
| 1092 | .pNext = nullptr, | ||
| 1093 | .flags = 0, | ||
| 1094 | .renderPass = renderpass, | ||
| 1095 | .attachmentCount = static_cast<u32>(attachments.size()), | ||
| 1096 | .pAttachments = attachments.data(), | ||
| 1097 | .width = key.size.width, | ||
| 1098 | .height = key.size.height, | ||
| 1099 | .layers = static_cast<u32>(num_layers), | ||
| 1100 | }); | ||
| 1101 | if (runtime.device.HasDebuggingToolAttached()) { | ||
| 1102 | framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str()); | ||
| 1103 | } | ||
| 615 | } | 1104 | } |
| 616 | 1105 | ||
| 617 | } // namespace Vulkan | 1106 | } // 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 b0be4cb0f..edc3d80c0 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -4,217 +4,265 @@ | |||
| 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" | 11 | #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" | 12 | #include "video_core/texture_cache/texture_cache.h" |
| 17 | 13 | ||
| 18 | namespace VideoCore { | ||
| 19 | class RasterizerInterface; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Vulkan { | 14 | namespace Vulkan { |
| 23 | 15 | ||
| 24 | class RasterizerVulkan; | 16 | using VideoCommon::ImageId; |
| 17 | using VideoCommon::NUM_RT; | ||
| 18 | using VideoCommon::Offset2D; | ||
| 19 | using VideoCommon::RenderTargets; | ||
| 20 | using VideoCore::Surface::PixelFormat; | ||
| 21 | |||
| 25 | class VKDevice; | 22 | class VKDevice; |
| 26 | class VKScheduler; | 23 | class VKScheduler; |
| 27 | class VKStagingBufferPool; | 24 | class VKStagingBufferPool; |
| 28 | 25 | ||
| 29 | class CachedSurfaceView; | 26 | class BlitImageHelper; |
| 30 | class CachedSurface; | 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 VKDevice& device; |
| 70 | } | 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(); | ||
| 71 | 79 | ||
| 72 | VkImage GetImageHandle() const { | 80 | [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size); |
| 73 | return *image->GetHandle(); | 81 | |
| 82 | [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size) { | ||
| 83 | // TODO: Have a special function for this | ||
| 84 | return MapUploadBuffer(size); | ||
| 74 | } | 85 | } |
| 75 | 86 | ||
| 76 | VkImageAspectFlags GetAspectMask() const { | 87 | void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 77 | return image->GetAspectMask(); | 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; | ||
| 78 | } | 99 | } |
| 79 | 100 | ||
| 80 | VkBufferView GetBufferViewHandle() const { | 101 | void AccelerateImageUpload(Image&, const ImageBufferMap&, size_t, |
| 81 | return *buffer_view; | 102 | std::span<const VideoCommon::SwizzleParameters>) { |
| 103 | UNREACHABLE(); | ||
| 82 | } | 104 | } |
| 83 | 105 | ||
| 84 | protected: | 106 | void InsertUploadMemoryBarrier() {} |
| 85 | void DecorateSurfaceName() override; | 107 | }; |
| 86 | 108 | ||
| 87 | View CreateView(const ViewParams& view_params) override; | 109 | class Image : public VideoCommon::ImageBase { |
| 110 | public: | ||
| 111 | explicit Image(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, GPUVAddr gpu_addr, | ||
| 112 | VAddr cpu_addr); | ||
| 88 | 113 | ||
| 89 | private: | 114 | void UploadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 90 | void UploadBuffer(const std::vector<u8>& staging_buffer); | 115 | std::span<const VideoCommon::BufferImageCopy> copies); |
| 91 | 116 | ||
| 92 | void UploadImage(const std::vector<u8>& staging_buffer); | 117 | void UploadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 118 | std::span<const VideoCommon::BufferCopy> copies); | ||
| 93 | 119 | ||
| 94 | VkBufferImageCopy GetBufferImageCopy(u32 level) const; | 120 | void DownloadMemory(const ImageBufferMap& map, size_t buffer_offset, |
| 121 | std::span<const VideoCommon::BufferImageCopy> copies); | ||
| 95 | 122 | ||
| 96 | VkImageSubresourceRange GetImageSubresourceRange() const; | 123 | [[nodiscard]] VkImage Handle() const noexcept { |
| 124 | return *image; | ||
| 125 | } | ||
| 97 | 126 | ||
| 98 | const VKDevice& device; | 127 | [[nodiscard]] VkBuffer Buffer() const noexcept { |
| 99 | VKMemoryManager& memory_manager; | 128 | return *buffer; |
| 100 | VKScheduler& scheduler; | 129 | } |
| 101 | VKStagingBufferPool& staging_pool; | 130 | |
| 131 | [[nodiscard]] VkImageCreateFlags AspectMask() const noexcept { | ||
| 132 | return aspect_mask; | ||
| 133 | } | ||
| 102 | 134 | ||
| 103 | std::optional<VKImage> image; | 135 | private: |
| 136 | VKScheduler* scheduler; | ||
| 137 | vk::Image image; | ||
| 104 | vk::Buffer buffer; | 138 | vk::Buffer buffer; |
| 105 | vk::BufferView buffer_view; | ||
| 106 | VKMemoryCommit commit; | 139 | VKMemoryCommit commit; |
| 107 | 140 | VkImageAspectFlags aspect_mask = 0; | |
| 108 | VkFormat format = VK_FORMAT_UNDEFINED; | 141 | bool initialized = false; |
| 109 | }; | 142 | }; |
| 110 | 143 | ||
| 111 | class CachedSurfaceView final : public VideoCommon::ViewBase { | 144 | class ImageView : public VideoCommon::ImageViewBase { |
| 112 | public: | 145 | public: |
| 113 | explicit CachedSurfaceView(const VKDevice& device_, CachedSurface& surface_, | 146 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); |
| 114 | const ViewParams& view_params_); | 147 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams&); |
| 115 | ~CachedSurfaceView(); | ||
| 116 | 148 | ||
| 117 | VkImageView GetImageView(Tegra::Texture::SwizzleSource x_source, | 149 | [[nodiscard]] VkImageView DepthView(); |
| 118 | Tegra::Texture::SwizzleSource y_source, | ||
| 119 | Tegra::Texture::SwizzleSource z_source, | ||
| 120 | Tegra::Texture::SwizzleSource w_source); | ||
| 121 | 150 | ||
| 122 | VkImageView GetAttachment(); | 151 | [[nodiscard]] VkImageView StencilView(); |
| 123 | 152 | ||
| 124 | bool IsSameSurface(const CachedSurfaceView& rhs) const { | 153 | [[nodiscard]] VkImageView Handle(VideoCommon::ImageViewType query_type) const noexcept { |
| 125 | return &surface == &rhs.surface; | 154 | return *image_views[static_cast<size_t>(query_type)]; |
| 126 | } | 155 | } |
| 127 | 156 | ||
| 128 | u32 GetWidth() const { | 157 | [[nodiscard]] VkBufferView BufferView() const noexcept { |
| 129 | return surface_params.GetMipWidth(base_level); | 158 | return *buffer_view; |
| 130 | } | 159 | } |
| 131 | 160 | ||
| 132 | u32 GetHeight() const { | 161 | [[nodiscard]] VkImage ImageHandle() const noexcept { |
| 133 | return surface_params.GetMipHeight(base_level); | 162 | return image_handle; |
| 134 | } | 163 | } |
| 135 | 164 | ||
| 136 | u32 GetNumLayers() const { | 165 | [[nodiscard]] VkImageView RenderTarget() const noexcept { |
| 137 | return num_layers; | 166 | return render_target; |
| 138 | } | 167 | } |
| 139 | 168 | ||
| 140 | bool IsBufferView() const { | 169 | [[nodiscard]] PixelFormat ImageFormat() const noexcept { |
| 141 | return buffer_view; | 170 | return image_format; |
| 142 | } | 171 | } |
| 143 | 172 | ||
| 144 | VkImage GetImage() const { | 173 | [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept { |
| 145 | return image; | 174 | return samples; |
| 146 | } | 175 | } |
| 147 | 176 | ||
| 148 | VkBufferView GetBufferView() const { | 177 | private: |
| 149 | return buffer_view; | 178 | [[nodiscard]] vk::ImageView MakeDepthStencilView(VkImageAspectFlags aspect_mask); |
| 150 | } | ||
| 151 | 179 | ||
| 152 | VkImageSubresourceRange GetImageSubresourceRange() const { | 180 | const VKDevice* device = nullptr; |
| 153 | return {aspect_mask, base_level, num_levels, base_layer, num_layers}; | 181 | std::array<vk::ImageView, VideoCommon::NUM_IMAGE_VIEW_TYPES> image_views; |
| 154 | } | 182 | vk::ImageView depth_view; |
| 183 | vk::ImageView stencil_view; | ||
| 184 | vk::BufferView buffer_view; | ||
| 185 | VkImage image_handle = VK_NULL_HANDLE; | ||
| 186 | VkImageView render_target = VK_NULL_HANDLE; | ||
| 187 | PixelFormat image_format = PixelFormat::Invalid; | ||
| 188 | VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; | ||
| 189 | }; | ||
| 155 | 190 | ||
| 156 | VkImageSubresourceLayers GetImageSubresourceLayers() const { | 191 | class ImageAlloc : public VideoCommon::ImageAllocBase {}; |
| 157 | return {surface.GetAspectMask(), base_level, base_layer, num_layers}; | ||
| 158 | } | ||
| 159 | 192 | ||
| 160 | void Transition(VkImageLayout new_layout, VkPipelineStageFlags new_stage_mask, | 193 | class Sampler { |
| 161 | VkAccessFlags new_access) const { | 194 | public: |
| 162 | surface.Transition(base_layer, num_layers, base_level, num_levels, new_stage_mask, | 195 | explicit Sampler(TextureCacheRuntime&, const Tegra::Texture::TSCEntry&); |
| 163 | new_access, new_layout); | ||
| 164 | } | ||
| 165 | 196 | ||
| 166 | void MarkAsModified(u64 tick) { | 197 | [[nodiscard]] VkSampler Handle() const noexcept { |
| 167 | surface.MarkAsModified(true, tick); | 198 | return *sampler; |
| 168 | } | 199 | } |
| 169 | 200 | ||
| 170 | private: | 201 | private: |
| 171 | // Store a copy of these values to avoid double dereference when reading them | 202 | vk::Sampler sampler; |
| 172 | const SurfaceParams surface_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 | }; | 203 | }; |
| 193 | 204 | ||
| 194 | class VKTextureCache final : public TextureCacheBase { | 205 | class Framebuffer { |
| 195 | public: | 206 | public: |
| 196 | explicit VKTextureCache(VideoCore::RasterizerInterface& rasterizer_, | 207 | explicit Framebuffer(TextureCacheRuntime&, std::span<ImageView*, NUM_RT> color_buffers, |
| 197 | Tegra::Engines::Maxwell3D& maxwell3d_, | 208 | ImageView* depth_buffer, const VideoCommon::RenderTargets& key); |
| 198 | Tegra::MemoryManager& gpu_memory_, const VKDevice& device_, | ||
| 199 | VKMemoryManager& memory_manager_, VKScheduler& scheduler_, | ||
| 200 | VKStagingBufferPool& staging_pool_); | ||
| 201 | ~VKTextureCache(); | ||
| 202 | 209 | ||
| 203 | private: | 210 | [[nodiscard]] VkFramebuffer Handle() const noexcept { |
| 204 | Surface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) override; | 211 | return *framebuffer; |
| 212 | } | ||
| 205 | 213 | ||
| 206 | void ImageCopy(Surface& src_surface, Surface& dst_surface, | 214 | [[nodiscard]] VkRenderPass RenderPass() const noexcept { |
| 207 | const VideoCommon::CopyParams& copy_params) override; | 215 | return renderpass; |
| 216 | } | ||
| 208 | 217 | ||
| 209 | void ImageBlit(View& src_view, View& dst_view, | 218 | [[nodiscard]] VkExtent2D RenderArea() const noexcept { |
| 210 | const Tegra::Engines::Fermi2D::Config& copy_config) override; | 219 | return render_area; |
| 220 | } | ||
| 211 | 221 | ||
| 212 | void BufferCopy(Surface& src_surface, Surface& dst_surface) override; | 222 | [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept { |
| 223 | return samples; | ||
| 224 | } | ||
| 213 | 225 | ||
| 214 | const VKDevice& device; | 226 | [[nodiscard]] u32 NumColorBuffers() const noexcept { |
| 215 | VKMemoryManager& memory_manager; | 227 | return num_color_buffers; |
| 216 | VKScheduler& scheduler; | 228 | } |
| 217 | VKStagingBufferPool& staging_pool; | 229 | |
| 230 | [[nodiscard]] u32 NumImages() const noexcept { | ||
| 231 | return num_images; | ||
| 232 | } | ||
| 233 | |||
| 234 | [[nodiscard]] const std::array<VkImage, 9>& Images() const noexcept { | ||
| 235 | return images; | ||
| 236 | } | ||
| 237 | |||
| 238 | [[nodiscard]] const std::array<VkImageSubresourceRange, 9>& ImageRanges() const noexcept { | ||
| 239 | return image_ranges; | ||
| 240 | } | ||
| 241 | |||
| 242 | private: | ||
| 243 | vk::Framebuffer framebuffer; | ||
| 244 | VkRenderPass renderpass{}; | ||
| 245 | VkExtent2D render_area{}; | ||
| 246 | VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; | ||
| 247 | u32 num_color_buffers = 0; | ||
| 248 | u32 num_images = 0; | ||
| 249 | std::array<VkImage, 9> images{}; | ||
| 250 | std::array<VkImageSubresourceRange, 9> image_ranges{}; | ||
| 251 | }; | ||
| 252 | |||
| 253 | struct TextureCacheParams { | ||
| 254 | static constexpr bool ENABLE_VALIDATION = true; | ||
| 255 | static constexpr bool FRAMEBUFFER_BLITS = false; | ||
| 256 | static constexpr bool HAS_EMULATED_COPIES = false; | ||
| 257 | |||
| 258 | using Runtime = Vulkan::TextureCacheRuntime; | ||
| 259 | using Image = Vulkan::Image; | ||
| 260 | using ImageAlloc = Vulkan::ImageAlloc; | ||
| 261 | using ImageView = Vulkan::ImageView; | ||
| 262 | using Sampler = Vulkan::Sampler; | ||
| 263 | using Framebuffer = Vulkan::Framebuffer; | ||
| 218 | }; | 264 | }; |
| 219 | 265 | ||
| 266 | using TextureCache = VideoCommon::TextureCache<TextureCacheParams>; | ||
| 267 | |||
| 220 | } // namespace Vulkan | 268 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h index f7e3c9821..f098a8540 100644 --- a/src/video_core/renderer_vulkan/vk_update_descriptor.h +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h | |||
| @@ -40,30 +40,34 @@ 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 VKDevice& device; |
| 69 | VKScheduler& scheduler; | 73 | VKScheduler& scheduler; |
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp index 1eced809e..2a21e850d 100644 --- a/src/video_core/renderer_vulkan/wrapper.cpp +++ b/src/video_core/renderer_vulkan/wrapper.cpp | |||
| @@ -81,6 +81,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 81 | X(vkCmdBeginQuery); | 81 | X(vkCmdBeginQuery); |
| 82 | X(vkCmdBeginRenderPass); | 82 | X(vkCmdBeginRenderPass); |
| 83 | X(vkCmdBeginTransformFeedbackEXT); | 83 | X(vkCmdBeginTransformFeedbackEXT); |
| 84 | X(vkCmdBeginDebugUtilsLabelEXT); | ||
| 84 | X(vkCmdBindDescriptorSets); | 85 | X(vkCmdBindDescriptorSets); |
| 85 | X(vkCmdBindIndexBuffer); | 86 | X(vkCmdBindIndexBuffer); |
| 86 | X(vkCmdBindPipeline); | 87 | X(vkCmdBindPipeline); |
| @@ -98,6 +99,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 98 | X(vkCmdEndQuery); | 99 | X(vkCmdEndQuery); |
| 99 | X(vkCmdEndRenderPass); | 100 | X(vkCmdEndRenderPass); |
| 100 | X(vkCmdEndTransformFeedbackEXT); | 101 | X(vkCmdEndTransformFeedbackEXT); |
| 102 | X(vkCmdEndDebugUtilsLabelEXT); | ||
| 101 | X(vkCmdFillBuffer); | 103 | X(vkCmdFillBuffer); |
| 102 | X(vkCmdPipelineBarrier); | 104 | X(vkCmdPipelineBarrier); |
| 103 | X(vkCmdPushConstants); | 105 | X(vkCmdPushConstants); |
| @@ -121,6 +123,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 121 | X(vkCmdSetPrimitiveTopologyEXT); | 123 | X(vkCmdSetPrimitiveTopologyEXT); |
| 122 | X(vkCmdSetStencilOpEXT); | 124 | X(vkCmdSetStencilOpEXT); |
| 123 | X(vkCmdSetStencilTestEnableEXT); | 125 | X(vkCmdSetStencilTestEnableEXT); |
| 126 | X(vkCmdResolveImage); | ||
| 124 | X(vkCreateBuffer); | 127 | X(vkCreateBuffer); |
| 125 | X(vkCreateBufferView); | 128 | X(vkCreateBufferView); |
| 126 | X(vkCreateCommandPool); | 129 | X(vkCreateCommandPool); |
| @@ -176,6 +179,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 176 | X(vkQueueSubmit); | 179 | X(vkQueueSubmit); |
| 177 | X(vkResetFences); | 180 | X(vkResetFences); |
| 178 | X(vkResetQueryPoolEXT); | 181 | X(vkResetQueryPoolEXT); |
| 182 | X(vkSetDebugUtilsObjectNameEXT); | ||
| 183 | X(vkSetDebugUtilsObjectTagEXT); | ||
| 179 | X(vkUnmapMemory); | 184 | X(vkUnmapMemory); |
| 180 | X(vkUpdateDescriptorSetWithTemplateKHR); | 185 | X(vkUpdateDescriptorSetWithTemplateKHR); |
| 181 | X(vkUpdateDescriptorSets); | 186 | X(vkUpdateDescriptorSets); |
| @@ -184,6 +189,19 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 184 | #undef X | 189 | #undef X |
| 185 | } | 190 | } |
| 186 | 191 | ||
| 192 | template <typename T> | ||
| 193 | void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjectType type, | ||
| 194 | const char* name) { | ||
| 195 | const VkDebugUtilsObjectNameInfoEXT name_info{ | ||
| 196 | .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, | ||
| 197 | .pNext = nullptr, | ||
| 198 | .objectType = VK_OBJECT_TYPE_IMAGE, | ||
| 199 | .objectHandle = reinterpret_cast<u64>(handle), | ||
| 200 | .pObjectName = name, | ||
| 201 | }; | ||
| 202 | Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); | ||
| 203 | } | ||
| 204 | |||
| 187 | } // Anonymous namespace | 205 | } // Anonymous namespace |
| 188 | 206 | ||
| 189 | bool Load(InstanceDispatch& dld) noexcept { | 207 | bool Load(InstanceDispatch& dld) noexcept { |
| @@ -476,8 +494,7 @@ DebugCallback Instance::TryCreateDebugCallback( | |||
| 476 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | | 494 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | |
| 477 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, | 495 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, |
| 478 | .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | | 496 | .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | |
| 479 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | | 497 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, |
| 480 | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, | ||
| 481 | .pfnUserCallback = callback, | 498 | .pfnUserCallback = callback, |
| 482 | .pUserData = nullptr, | 499 | .pUserData = nullptr, |
| 483 | }; | 500 | }; |
| @@ -493,10 +510,38 @@ void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | |||
| 493 | Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); | 510 | Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); |
| 494 | } | 511 | } |
| 495 | 512 | ||
| 513 | void Buffer::SetObjectNameEXT(const char* name) const { | ||
| 514 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); | ||
| 515 | } | ||
| 516 | |||
| 517 | void BufferView::SetObjectNameEXT(const char* name) const { | ||
| 518 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); | ||
| 519 | } | ||
| 520 | |||
| 496 | void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | 521 | void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { |
| 497 | Check(dld->vkBindImageMemory(owner, handle, memory, offset)); | 522 | Check(dld->vkBindImageMemory(owner, handle, memory, offset)); |
| 498 | } | 523 | } |
| 499 | 524 | ||
| 525 | void Image::SetObjectNameEXT(const char* name) const { | ||
| 526 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); | ||
| 527 | } | ||
| 528 | |||
| 529 | void ImageView::SetObjectNameEXT(const char* name) const { | ||
| 530 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE_VIEW, name); | ||
| 531 | } | ||
| 532 | |||
| 533 | void DeviceMemory::SetObjectNameEXT(const char* name) const { | ||
| 534 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DEVICE_MEMORY, name); | ||
| 535 | } | ||
| 536 | |||
| 537 | void Fence::SetObjectNameEXT(const char* name) const { | ||
| 538 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FENCE, name); | ||
| 539 | } | ||
| 540 | |||
| 541 | void Framebuffer::SetObjectNameEXT(const char* name) const { | ||
| 542 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FRAMEBUFFER, name); | ||
| 543 | } | ||
| 544 | |||
| 500 | DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const { | 545 | DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const { |
| 501 | const std::size_t num = ai.descriptorSetCount; | 546 | const std::size_t num = ai.descriptorSetCount; |
| 502 | std::unique_ptr sets = std::make_unique<VkDescriptorSet[]>(num); | 547 | std::unique_ptr sets = std::make_unique<VkDescriptorSet[]>(num); |
| @@ -510,6 +555,10 @@ DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) c | |||
| 510 | } | 555 | } |
| 511 | } | 556 | } |
| 512 | 557 | ||
| 558 | void DescriptorPool::SetObjectNameEXT(const char* name) const { | ||
| 559 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DESCRIPTOR_POOL, name); | ||
| 560 | } | ||
| 561 | |||
| 513 | CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const { | 562 | CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const { |
| 514 | const VkCommandBufferAllocateInfo ai{ | 563 | const VkCommandBufferAllocateInfo ai{ |
| 515 | .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | 564 | .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, |
| @@ -530,6 +579,10 @@ CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLev | |||
| 530 | } | 579 | } |
| 531 | } | 580 | } |
| 532 | 581 | ||
| 582 | void CommandPool::SetObjectNameEXT(const char* name) const { | ||
| 583 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_COMMAND_POOL, name); | ||
| 584 | } | ||
| 585 | |||
| 533 | std::vector<VkImage> SwapchainKHR::GetImages() const { | 586 | std::vector<VkImage> SwapchainKHR::GetImages() const { |
| 534 | u32 num; | 587 | u32 num; |
| 535 | Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr)); | 588 | Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr)); |
| @@ -538,6 +591,18 @@ std::vector<VkImage> SwapchainKHR::GetImages() const { | |||
| 538 | return images; | 591 | return images; |
| 539 | } | 592 | } |
| 540 | 593 | ||
| 594 | void Event::SetObjectNameEXT(const char* name) const { | ||
| 595 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_EVENT, name); | ||
| 596 | } | ||
| 597 | |||
| 598 | void ShaderModule::SetObjectNameEXT(const char* name) const { | ||
| 599 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SHADER_MODULE, name); | ||
| 600 | } | ||
| 601 | |||
| 602 | void Semaphore::SetObjectNameEXT(const char* name) const { | ||
| 603 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SEMAPHORE, name); | ||
| 604 | } | ||
| 605 | |||
| 541 | Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, | 606 | Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, |
| 542 | Span<const char*> enabled_extensions, const void* next, | 607 | Span<const char*> enabled_extensions, const void* next, |
| 543 | DeviceDispatch& dispatch) noexcept { | 608 | DeviceDispatch& dispatch) noexcept { |
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h index 76f790eab..f9a184e00 100644 --- a/src/video_core/renderer_vulkan/wrapper.h +++ b/src/video_core/renderer_vulkan/wrapper.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <limits> | 9 | #include <limits> |
| 10 | #include <memory> | 10 | #include <memory> |
| 11 | #include <optional> | 11 | #include <optional> |
| 12 | #include <span> | ||
| 12 | #include <type_traits> | 13 | #include <type_traits> |
| 13 | #include <utility> | 14 | #include <utility> |
| 14 | #include <vector> | 15 | #include <vector> |
| @@ -18,6 +19,10 @@ | |||
| 18 | 19 | ||
| 19 | #include "common/common_types.h" | 20 | #include "common/common_types.h" |
| 20 | 21 | ||
| 22 | #ifdef _MSC_VER | ||
| 23 | #pragma warning(disable : 26812) // Disable prefer enum class over enum | ||
| 24 | #endif | ||
| 25 | |||
| 21 | namespace Vulkan::vk { | 26 | namespace Vulkan::vk { |
| 22 | 27 | ||
| 23 | /** | 28 | /** |
| @@ -41,6 +46,9 @@ public: | |||
| 41 | /// Construct an empty span. | 46 | /// Construct an empty span. |
| 42 | constexpr Span() noexcept = default; | 47 | constexpr Span() noexcept = default; |
| 43 | 48 | ||
| 49 | /// Construct an empty span | ||
| 50 | constexpr Span(std::nullptr_t) noexcept {} | ||
| 51 | |||
| 44 | /// Construct a span from a single element. | 52 | /// Construct a span from a single element. |
| 45 | constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {} | 53 | constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {} |
| 46 | 54 | ||
| @@ -177,6 +185,7 @@ struct DeviceDispatch : public InstanceDispatch { | |||
| 177 | PFN_vkCmdBeginQuery vkCmdBeginQuery; | 185 | PFN_vkCmdBeginQuery vkCmdBeginQuery; |
| 178 | PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; | 186 | PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; |
| 179 | PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; | 187 | PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; |
| 188 | PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; | ||
| 180 | PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; | 189 | PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; |
| 181 | PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; | 190 | PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; |
| 182 | PFN_vkCmdBindPipeline vkCmdBindPipeline; | 191 | PFN_vkCmdBindPipeline vkCmdBindPipeline; |
| @@ -194,6 +203,7 @@ struct DeviceDispatch : public InstanceDispatch { | |||
| 194 | PFN_vkCmdEndQuery vkCmdEndQuery; | 203 | PFN_vkCmdEndQuery vkCmdEndQuery; |
| 195 | PFN_vkCmdEndRenderPass vkCmdEndRenderPass; | 204 | PFN_vkCmdEndRenderPass vkCmdEndRenderPass; |
| 196 | PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; | 205 | PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; |
| 206 | PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; | ||
| 197 | PFN_vkCmdFillBuffer vkCmdFillBuffer; | 207 | PFN_vkCmdFillBuffer vkCmdFillBuffer; |
| 198 | PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; | 208 | PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; |
| 199 | PFN_vkCmdPushConstants vkCmdPushConstants; | 209 | PFN_vkCmdPushConstants vkCmdPushConstants; |
| @@ -217,6 +227,7 @@ struct DeviceDispatch : public InstanceDispatch { | |||
| 217 | PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; | 227 | PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; |
| 218 | PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; | 228 | PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; |
| 219 | PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; | 229 | PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; |
| 230 | PFN_vkCmdResolveImage vkCmdResolveImage; | ||
| 220 | PFN_vkCreateBuffer vkCreateBuffer; | 231 | PFN_vkCreateBuffer vkCreateBuffer; |
| 221 | PFN_vkCreateBufferView vkCreateBufferView; | 232 | PFN_vkCreateBufferView vkCreateBufferView; |
| 222 | PFN_vkCreateCommandPool vkCreateCommandPool; | 233 | PFN_vkCreateCommandPool vkCreateCommandPool; |
| @@ -272,6 +283,8 @@ struct DeviceDispatch : public InstanceDispatch { | |||
| 272 | PFN_vkQueueSubmit vkQueueSubmit; | 283 | PFN_vkQueueSubmit vkQueueSubmit; |
| 273 | PFN_vkResetFences vkResetFences; | 284 | PFN_vkResetFences vkResetFences; |
| 274 | PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; | 285 | PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; |
| 286 | PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; | ||
| 287 | PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; | ||
| 275 | PFN_vkUnmapMemory vkUnmapMemory; | 288 | PFN_vkUnmapMemory vkUnmapMemory; |
| 276 | PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; | 289 | PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; |
| 277 | PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; | 290 | PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; |
| @@ -542,18 +555,14 @@ private: | |||
| 542 | const DeviceDispatch* dld = nullptr; | 555 | const DeviceDispatch* dld = nullptr; |
| 543 | }; | 556 | }; |
| 544 | 557 | ||
| 545 | using BufferView = Handle<VkBufferView, VkDevice, DeviceDispatch>; | ||
| 546 | using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; | 558 | using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; |
| 547 | using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; | 559 | using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; |
| 548 | using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>; | 560 | using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>; |
| 549 | using Framebuffer = Handle<VkFramebuffer, VkDevice, DeviceDispatch>; | ||
| 550 | using ImageView = Handle<VkImageView, VkDevice, DeviceDispatch>; | ||
| 551 | using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; | 561 | using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; |
| 552 | using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>; | 562 | using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>; |
| 553 | using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; | 563 | using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; |
| 554 | using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>; | 564 | using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>; |
| 555 | using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>; | 565 | using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>; |
| 556 | using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>; | ||
| 557 | using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>; | 566 | using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>; |
| 558 | 567 | ||
| 559 | using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>; | 568 | using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>; |
| @@ -605,6 +614,17 @@ class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> { | |||
| 605 | public: | 614 | public: |
| 606 | /// Attaches a memory allocation. | 615 | /// Attaches a memory allocation. |
| 607 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | 616 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; |
| 617 | |||
| 618 | /// Set object name. | ||
| 619 | void SetObjectNameEXT(const char* name) const; | ||
| 620 | }; | ||
| 621 | |||
| 622 | class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { | ||
| 623 | using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; | ||
| 624 | |||
| 625 | public: | ||
| 626 | /// Set object name. | ||
| 627 | void SetObjectNameEXT(const char* name) const; | ||
| 608 | }; | 628 | }; |
| 609 | 629 | ||
| 610 | class Image : public Handle<VkImage, VkDevice, DeviceDispatch> { | 630 | class Image : public Handle<VkImage, VkDevice, DeviceDispatch> { |
| @@ -613,12 +633,26 @@ class Image : public Handle<VkImage, VkDevice, DeviceDispatch> { | |||
| 613 | public: | 633 | public: |
| 614 | /// Attaches a memory allocation. | 634 | /// Attaches a memory allocation. |
| 615 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | 635 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; |
| 636 | |||
| 637 | /// Set object name. | ||
| 638 | void SetObjectNameEXT(const char* name) const; | ||
| 639 | }; | ||
| 640 | |||
| 641 | class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> { | ||
| 642 | using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle; | ||
| 643 | |||
| 644 | public: | ||
| 645 | /// Set object name. | ||
| 646 | void SetObjectNameEXT(const char* name) const; | ||
| 616 | }; | 647 | }; |
| 617 | 648 | ||
| 618 | class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> { | 649 | class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> { |
| 619 | using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle; | 650 | using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle; |
| 620 | 651 | ||
| 621 | public: | 652 | public: |
| 653 | /// Set object name. | ||
| 654 | void SetObjectNameEXT(const char* name) const; | ||
| 655 | |||
| 622 | u8* Map(VkDeviceSize offset, VkDeviceSize size) const { | 656 | u8* Map(VkDeviceSize offset, VkDeviceSize size) const { |
| 623 | void* data; | 657 | void* data; |
| 624 | Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data)); | 658 | Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data)); |
| @@ -634,6 +668,9 @@ class Fence : public Handle<VkFence, VkDevice, DeviceDispatch> { | |||
| 634 | using Handle<VkFence, VkDevice, DeviceDispatch>::Handle; | 668 | using Handle<VkFence, VkDevice, DeviceDispatch>::Handle; |
| 635 | 669 | ||
| 636 | public: | 670 | public: |
| 671 | /// Set object name. | ||
| 672 | void SetObjectNameEXT(const char* name) const; | ||
| 673 | |||
| 637 | VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept { | 674 | VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept { |
| 638 | return dld->vkWaitForFences(owner, 1, &handle, true, timeout); | 675 | return dld->vkWaitForFences(owner, 1, &handle, true, timeout); |
| 639 | } | 676 | } |
| @@ -647,11 +684,22 @@ public: | |||
| 647 | } | 684 | } |
| 648 | }; | 685 | }; |
| 649 | 686 | ||
| 687 | class Framebuffer : public Handle<VkFramebuffer, VkDevice, DeviceDispatch> { | ||
| 688 | using Handle<VkFramebuffer, VkDevice, DeviceDispatch>::Handle; | ||
| 689 | |||
| 690 | public: | ||
| 691 | /// Set object name. | ||
| 692 | void SetObjectNameEXT(const char* name) const; | ||
| 693 | }; | ||
| 694 | |||
| 650 | class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> { | 695 | class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> { |
| 651 | using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle; | 696 | using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle; |
| 652 | 697 | ||
| 653 | public: | 698 | public: |
| 654 | DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const; | 699 | DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const; |
| 700 | |||
| 701 | /// Set object name. | ||
| 702 | void SetObjectNameEXT(const char* name) const; | ||
| 655 | }; | 703 | }; |
| 656 | 704 | ||
| 657 | class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> { | 705 | class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> { |
| @@ -660,6 +708,9 @@ class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> { | |||
| 660 | public: | 708 | public: |
| 661 | CommandBuffers Allocate(std::size_t num_buffers, | 709 | CommandBuffers Allocate(std::size_t num_buffers, |
| 662 | VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const; | 710 | VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const; |
| 711 | |||
| 712 | /// Set object name. | ||
| 713 | void SetObjectNameEXT(const char* name) const; | ||
| 663 | }; | 714 | }; |
| 664 | 715 | ||
| 665 | class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> { | 716 | class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> { |
| @@ -673,15 +724,29 @@ class Event : public Handle<VkEvent, VkDevice, DeviceDispatch> { | |||
| 673 | using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle; | 724 | using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle; |
| 674 | 725 | ||
| 675 | public: | 726 | public: |
| 727 | /// Set object name. | ||
| 728 | void SetObjectNameEXT(const char* name) const; | ||
| 729 | |||
| 676 | VkResult GetStatus() const noexcept { | 730 | VkResult GetStatus() const noexcept { |
| 677 | return dld->vkGetEventStatus(owner, handle); | 731 | return dld->vkGetEventStatus(owner, handle); |
| 678 | } | 732 | } |
| 679 | }; | 733 | }; |
| 680 | 734 | ||
| 735 | class ShaderModule : public Handle<VkShaderModule, VkDevice, DeviceDispatch> { | ||
| 736 | using Handle<VkShaderModule, VkDevice, DeviceDispatch>::Handle; | ||
| 737 | |||
| 738 | public: | ||
| 739 | /// Set object name. | ||
| 740 | void SetObjectNameEXT(const char* name) const; | ||
| 741 | }; | ||
| 742 | |||
| 681 | class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> { | 743 | class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> { |
| 682 | using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle; | 744 | using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle; |
| 683 | 745 | ||
| 684 | public: | 746 | public: |
| 747 | /// Set object name. | ||
| 748 | void SetObjectNameEXT(const char* name) const; | ||
| 749 | |||
| 685 | [[nodiscard]] u64 GetCounter() const { | 750 | [[nodiscard]] u64 GetCounter() const { |
| 686 | u64 value; | 751 | u64 value; |
| 687 | Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value)); | 752 | Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value)); |
| @@ -932,6 +997,12 @@ public: | |||
| 932 | regions.data(), filter); | 997 | regions.data(), filter); |
| 933 | } | 998 | } |
| 934 | 999 | ||
| 1000 | void ResolveImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, | ||
| 1001 | VkImageLayout dst_layout, Span<VkImageResolve> regions) { | ||
| 1002 | dld->vkCmdResolveImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), | ||
| 1003 | regions.data()); | ||
| 1004 | } | ||
| 1005 | |||
| 935 | void Dispatch(u32 x, u32 y, u32 z) const noexcept { | 1006 | void Dispatch(u32 x, u32 y, u32 z) const noexcept { |
| 936 | dld->vkCmdDispatch(handle, x, y, z); | 1007 | dld->vkCmdDispatch(handle, x, y, z); |
| 937 | } | 1008 | } |
| @@ -946,6 +1017,23 @@ public: | |||
| 946 | image_barriers.size(), image_barriers.data()); | 1017 | image_barriers.size(), image_barriers.data()); |
| 947 | } | 1018 | } |
| 948 | 1019 | ||
| 1020 | void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, | ||
| 1021 | VkDependencyFlags dependency_flags = 0) const noexcept { | ||
| 1022 | PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, {}); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, | ||
| 1026 | VkDependencyFlags dependency_flags, | ||
| 1027 | const VkBufferMemoryBarrier& buffer_barrier) const noexcept { | ||
| 1028 | PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, buffer_barrier, {}); | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, | ||
| 1032 | VkDependencyFlags dependency_flags, | ||
| 1033 | const VkImageMemoryBarrier& image_barrier) const noexcept { | ||
| 1034 | PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, image_barrier); | ||
| 1035 | } | ||
| 1036 | |||
| 949 | void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout, | 1037 | void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout, |
| 950 | Span<VkBufferImageCopy> regions) const noexcept { | 1038 | Span<VkBufferImageCopy> regions) const noexcept { |
| 951 | dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(), | 1039 | dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(), |
| @@ -979,6 +1067,13 @@ public: | |||
| 979 | dld->vkCmdPushConstants(handle, layout, flags, offset, size, values); | 1067 | dld->vkCmdPushConstants(handle, layout, flags, offset, size, values); |
| 980 | } | 1068 | } |
| 981 | 1069 | ||
| 1070 | template <typename T> | ||
| 1071 | void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, | ||
| 1072 | const T& data) const noexcept { | ||
| 1073 | static_assert(std::is_trivially_copyable_v<T>, "<data> is not trivially copyable"); | ||
| 1074 | dld->vkCmdPushConstants(handle, layout, flags, 0, static_cast<u32>(sizeof(T)), &data); | ||
| 1075 | } | ||
| 1076 | |||
| 982 | void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept { | 1077 | void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept { |
| 983 | dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data()); | 1078 | dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data()); |
| 984 | } | 1079 | } |
| @@ -1088,6 +1183,20 @@ public: | |||
| 1088 | counter_buffers, counter_buffer_offsets); | 1183 | counter_buffers, counter_buffer_offsets); |
| 1089 | } | 1184 | } |
| 1090 | 1185 | ||
| 1186 | void BeginDebugUtilsLabelEXT(const char* label, std::span<float, 4> color) const noexcept { | ||
| 1187 | const VkDebugUtilsLabelEXT label_info{ | ||
| 1188 | .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, | ||
| 1189 | .pNext = nullptr, | ||
| 1190 | .pLabelName = label, | ||
| 1191 | .color{color[0], color[1], color[2], color[3]}, | ||
| 1192 | }; | ||
| 1193 | dld->vkCmdBeginDebugUtilsLabelEXT(handle, &label_info); | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | void EndDebugUtilsLabelEXT() const noexcept { | ||
| 1197 | dld->vkCmdEndDebugUtilsLabelEXT(handle); | ||
| 1198 | } | ||
| 1199 | |||
| 1091 | private: | 1200 | private: |
| 1092 | VkCommandBuffer handle; | 1201 | VkCommandBuffer handle; |
| 1093 | const DeviceDispatch* dld; | 1202 | const DeviceDispatch* dld; |