vk_image.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <memory>
  5. #include <vector>
  6. #include "common/assert.h"
  7. #include "video_core/renderer_vulkan/vk_device.h"
  8. #include "video_core/renderer_vulkan/vk_image.h"
  9. #include "video_core/renderer_vulkan/vk_scheduler.h"
  10. #include "video_core/renderer_vulkan/wrapper.h"
  11. namespace Vulkan {
  12. VKImage::VKImage(const VKDevice& device, VKScheduler& scheduler, const VkImageCreateInfo& image_ci,
  13. VkImageAspectFlags aspect_mask)
  14. : device{device}, scheduler{scheduler}, format{image_ci.format}, aspect_mask{aspect_mask},
  15. image_num_layers{image_ci.arrayLayers}, image_num_levels{image_ci.mipLevels} {
  16. UNIMPLEMENTED_IF_MSG(image_ci.queueFamilyIndexCount != 0,
  17. "Queue family tracking is not implemented");
  18. image = device.GetLogical().CreateImage(image_ci);
  19. const u32 num_ranges = image_num_layers * image_num_levels;
  20. barriers.resize(num_ranges);
  21. subrange_states.resize(num_ranges, {{}, image_ci.initialLayout});
  22. }
  23. VKImage::~VKImage() = default;
  24. void VKImage::Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels,
  25. VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access,
  26. VkImageLayout new_layout) {
  27. if (!HasChanged(base_layer, num_layers, base_level, num_levels, new_access, new_layout)) {
  28. return;
  29. }
  30. std::size_t cursor = 0;
  31. for (u32 layer_it = 0; layer_it < num_layers; ++layer_it) {
  32. for (u32 level_it = 0; level_it < num_levels; ++level_it, ++cursor) {
  33. const u32 layer = base_layer + layer_it;
  34. const u32 level = base_level + level_it;
  35. auto& state = GetSubrangeState(layer, level);
  36. auto& barrier = barriers[cursor];
  37. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  38. barrier.pNext = nullptr;
  39. barrier.srcAccessMask = state.access;
  40. barrier.dstAccessMask = new_access;
  41. barrier.oldLayout = state.layout;
  42. barrier.newLayout = new_layout;
  43. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  44. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  45. barrier.image = *image;
  46. barrier.subresourceRange.aspectMask = aspect_mask;
  47. barrier.subresourceRange.baseMipLevel = level;
  48. barrier.subresourceRange.levelCount = 1;
  49. barrier.subresourceRange.baseArrayLayer = layer;
  50. barrier.subresourceRange.layerCount = 1;
  51. state.access = new_access;
  52. state.layout = new_layout;
  53. }
  54. }
  55. scheduler.RequestOutsideRenderPassOperationContext();
  56. scheduler.Record([barriers = barriers, cursor](vk::CommandBuffer cmdbuf) {
  57. // TODO(Rodrigo): Implement a way to use the latest stage across subresources.
  58. cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
  59. VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, {}, {},
  60. vk::Span(barriers.data(), cursor));
  61. });
  62. }
  63. bool VKImage::HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels,
  64. VkAccessFlags new_access, VkImageLayout new_layout) noexcept {
  65. const bool is_full_range = base_layer == 0 && num_layers == image_num_layers &&
  66. base_level == 0 && num_levels == image_num_levels;
  67. if (!is_full_range) {
  68. state_diverged = true;
  69. }
  70. if (!state_diverged) {
  71. auto& state = GetSubrangeState(0, 0);
  72. if (state.access != new_access || state.layout != new_layout) {
  73. return true;
  74. }
  75. }
  76. for (u32 layer_it = 0; layer_it < num_layers; ++layer_it) {
  77. for (u32 level_it = 0; level_it < num_levels; ++level_it) {
  78. const u32 layer = base_layer + layer_it;
  79. const u32 level = base_level + level_it;
  80. auto& state = GetSubrangeState(layer, level);
  81. if (state.access != new_access || state.layout != new_layout) {
  82. return true;
  83. }
  84. }
  85. }
  86. return false;
  87. }
  88. void VKImage::CreatePresentView() {
  89. // Image type has to be 2D to be presented.
  90. VkImageViewCreateInfo image_view_ci;
  91. image_view_ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  92. image_view_ci.pNext = nullptr;
  93. image_view_ci.flags = 0;
  94. image_view_ci.image = *image;
  95. image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
  96. image_view_ci.format = format;
  97. image_view_ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
  98. VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
  99. image_view_ci.subresourceRange.aspectMask = aspect_mask;
  100. image_view_ci.subresourceRange.baseMipLevel = 0;
  101. image_view_ci.subresourceRange.levelCount = 1;
  102. image_view_ci.subresourceRange.baseArrayLayer = 0;
  103. image_view_ci.subresourceRange.layerCount = 1;
  104. present_view = device.GetLogical().CreateImageView(image_view_ci);
  105. }
  106. VKImage::SubrangeState& VKImage::GetSubrangeState(u32 layer, u32 level) noexcept {
  107. return subrange_states[static_cast<std::size_t>(layer * image_num_levels) +
  108. static_cast<std::size_t>(level)];
  109. }
  110. } // namespace Vulkan